한 가지 주요 차이점은 예외 전파입니다. 내부 던져진 예외 상황, async Task
방법, 반환에 저장됩니다 Task
객체와 작업을 통해 관찰 때까지 휴면 남아 await task
, task.Wait()
, task.Result
또는 task.GetAwaiter().GetResult()
. 메서드 의 동기 부분 에서 throw 되더라도 이러한 방식으로 전파 async
됩니다.
다음 코드를 고려 곳 OneTestAsync
과 AnotherTestAsync
상당히 다르게 동작 :
static async Task OneTestAsync(int n)
{
await Task.Delay(n);
}
static Task AnotherTestAsync(int n)
{
return Task.Delay(n);
}
static void DoTestAsync(Func<int, Task> whatTest, int n)
{
Task task = null;
try
{
task = whatTest(n);
Console.Write("Press enter to continue");
Console.ReadLine();
task.Wait();
}
catch (Exception ex)
{
Console.Write("Error: " + ex.Message);
}
}
을 호출 DoTestAsync(OneTestAsync, -2)
하면 다음과 같은 출력이 생성됩니다.
계속하려면 Enter 키를 누르세요.
오류 : 하나 이상의 오류가 발생했습니다. await Task.Delay
오류 : 두 번째
나는 Enter그것을보기 위해 눌러야 했다.
이제를 호출하면 DoTestAsync(AnotherTestAsync, -2)
내부의 코드 워크 플로 DoTestAsync
가 상당히 다르며 출력도 마찬가지입니다. 이번에는 다음을 누르라는 요청을받지 않았습니다 Enter.
오류 : 값은 -1 (무한 제한 시간을 의미), 0 또는 양의 정수 여야합니다.
매개 변수 이름 : millisecondsDelayError : 1st
두 경우 모두 Task.Delay(-2)
매개 변수의 유효성을 검사하면서 처음에 발생합니다. 이것은 구성 시나리오 일 수 있지만 이론적으로 Task.Delay(1000)
는 예를 들어 기본 시스템 타이머 API가 실패하는 경우에도 발생할 수 있습니다.
참고로, 오류 전파 논리는 async void
메서드 ( 메소드 와 반대)에 대해 아직 다릅니다 async Task
. async void
메서드 내에서 발생한 예외 SynchronizationContext.Post
는 현재 스레드가 하나 ( SynchronizationContext.Current != null)
. 그렇지 않으면를 통해 다시 throw됩니다 ThreadPool.QueueUserWorkItem
. 호출자는 동일한 스택 프레임에서이 예외를 처리 할 기회가 없습니다.
여기 와 여기 에 TPL 예외 처리 동작에 대한 자세한 내용을 게시했습니다 .
Q : async
비동기 Task
기반이 아닌 메서드에 대한 메서드 의 예외 전파 동작을 모방 하여 후자가 동일한 스택 프레임에서 발생하지 않도록 할 수 있습니까?
A : 정말로 필요한 경우, 예, 이에 대한 트릭이 있습니다.
async Task<int> MethodAsync(int arg)
{
if (arg < 0)
throw new ArgumentException("arg");
return 42 + arg;
}
Task<int> MethodAsync(int arg)
{
var task = new Task<int>(() =>
{
if (arg < 0)
throw new ArgumentException("arg");
return 42 + arg;
});
task.RunSynchronously(TaskScheduler.Default);
return task;
}
그러나 특정 조건 (예 : 스택에 너무 깊숙한 경우)에서는 RunSynchronously
여전히 비동기 적으로 실행될 수 있습니다.
또 다른 주목할만한 차이가 있다는 것입니다
/의 버전은 죽은 잠금이 아닌 기본 동기화 상황에 더 많은 경향이있다 . 예를 들어 다음은 WinForms 또는 WPF 응용 프로그램에서 교착 상태가됩니다.
async
await
static async Task TestAsync()
{
await Task.Delay(1000);
}
void Form_Load(object sender, EventArgs e)
{
TestAsync().Wait();
}
비동기 버전으로 변경하면 교착 상태가되지 않습니다.
Task TestAsync()
{
return Task.Delay(1000);
}
교착 상태의 특성은 그의 블로그 에서 Stephen Cleary에 의해 잘 설명됩니다 .
await
/를async
모든 :)에서