我的方法返回一个
Task
。我想等待它完成。我应该使用.Wait()
还是.GetAwaiter().GetResult()
?它们之间有什么区别?Task
。我想等待它完成。我应该使用.Wait()
还是.GetAwaiter().GetResult()
?它们之间有什么区别?两者都会同步等待操作结果(如果可能,应该避免使用它们)。
区别主要在于异常处理。使用Wait
方法时,异常堆栈跟踪未被修改,并表示异常发生时的实际堆栈,因此,如果您的代码在线程池线程上运行,则堆栈将类似于:
ThreadPoolThread.RunTask
YourCode.SomeWork
另一方面,.GetAwaiter().GetResult()
将重构堆栈跟踪以考虑所有异步上下文,忽略某些代码部分在UI线程上执行,某些在ThreadPool线程上执行,而有些则是简单的异步I/O。因此,您的堆栈跟踪将反映对您的代码类似于同步的步骤:
TheSyncMethodThatWaitsForTheAsyncMethod
YourCode.SomeAsyncMethod
SomeAsync
YourCode.SomeWork
这往往会使异常堆栈跟踪变得更加有用,可以说是至关重要的。您可以看到 YourCode.SomeWork
在您应用程序的上下文中被调用,而不是“物理运行方式”。
这种工作原理的示例在参考源代码中有展示(当然,这不是合同文件)。
尽力避免在异步任务上同步阻塞。
在那些罕见的例外情况下,GetAwaiter().GetResult()
将保留任务异常。
如果使用Wait
会抛出AggregateException异常。
TaskAwaiter
是一个实现细节。另一方面,可等待/等待器机制已经有文档并且是使用鸭子类型的——GetAwaiter
相当于GetEnumerator
对于foreach
或者Dispose
对于using
。这些都在C#规范中定义了,无论使用哪种特定的等待器 - 注意,Task.GetAwaiter
是 "旨在供编译器使用而不是应用程序代码使用"。但关键是预期使用的是await
,而不是Wait()
或者GetAwaiter().GetResult()
——但如果需要的话,GetResult
可以给你更好的堆栈信息。 - Luaanusing
和Dispose()
不使用鸭子类型。只有在实现IDisposable
时才有效。而foreach
和GetEnumerator()
以及await
和GetAwaiter()
则使用鸭子类型。 - codingdave