비동기식 프로그래밍은 코드베이스를 통해 "성장"합니다. 좀비 바이러스와 비교 되었습니다 . 가장 좋은 해결책은 그것이 자라도록하는 것이지만 때로는 불가능합니다.
Nito.AsyncEx 라이브러리에 부분적으로 비동기 코드 기반을 처리하기 위해 몇 가지 유형을 작성했습니다 . 그러나 모든 상황에서 작동하는 솔루션은 없습니다.
해결책 A
컨텍스트와 다시 동기화 할 필요가없는 간단한 비동기 메소드가있는 경우 다음을 사용할 수 있습니다 Task.WaitAndUnwrapException
.
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
당신은 할 수 없습니다 사용하려는 Task.Wait
또는 Task.Result
그들이에 예외를 포장하기 때문에 AggregateException
.
이 솔루션은 MyAsyncMethod
컨텍스트와 다시 동기화되지 않는 경우에만 적합합니다 . 다시 말해서 모든 await
로 MyAsyncMethod
끝나야합니다 ConfigureAwait(false)
. 즉, UI 요소를 업데이트하거나 ASP.NET 요청 컨텍스트에 액세스 할 수 없습니다.
솔루션 B
MyAsyncMethod
컨텍스트와 다시 동기화해야하는 경우 AsyncContext.RunTask
중첩 된 컨텍스트를 제공하는 데 사용할 수 있습니다 .
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
* 2014 년 4 월 14 일 업데이트 : 최신 버전의 라이브러리에서 API는 다음과 같습니다.
var result = AsyncContext.Run(MyAsyncMethod);
( 예외 를 전파하므로이 Task.Result
예제에서 사용 하는 것이 좋습니다 ).RunTask
Task
AsyncContext.RunTask
대신에 필요한 이유 Task.WaitAndUnwrapException
는 WinForms / WPF / SL / ASP.NET에서 발생할 수있는 약간의 교착 상태 가능성 때문입니다.
- 동기 메서드는 async 메서드를 호출하여를 얻습니다
Task
.
- 동기 메소드는에서 블로킹 대기를 수행합니다
Task
.
- 이
async
방법은 await
없이 사용합니다 ConfigureAwait
.
- 는
Task
때만 완료하기 때문에이 상황에서 완료 할 수 없습니다 async
방법은 완성입니다 에 async
대한 연속을 예약하려고 시도하기 때문에이 메서드를 완료 할 수 없으며 SynchronizationContext
동기식 메서드가 해당 컨텍스트에서 이미 실행 중이므로 WinForms / WPF / SL / ASP.NET에서 연속을 실행할 수 없습니다.
이것이 ConfigureAwait(false)
모든 async
방법 내에서 가능한 한 많이 사용하는 것이 좋은 이유 입니다.
솔루션 C
AsyncContext.RunTask
모든 시나리오에서 작동하지는 않습니다. 예를 들어, async
메소드가 UI 이벤트를 완료해야하는 무언가를 기다리는 경우 중첩 된 컨텍스트에서도 교착 상태가 발생합니다. 이 경우 async
스레드 풀 에서 메소드를 시작할 수 있습니다.
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
그러나이 솔루션에는 MyAsyncMethod
스레드 풀 컨텍스트에서 작동 하는 솔루션이 필요합니다 . 따라서 UI 요소를 업데이트하거나 ASP.NET 요청 컨텍스트에 액세스 할 수 없습니다. 이 경우 ConfigureAwait(false)
해당 await
설명을 추가 하고 솔루션 A를 사용할 수 있습니다.
2019 년 5 월 1 일 업데이트 : 최신 "최악의 사례"는 MSDN 기사 here에 있습니다 .