它是并发的,从某种意义上说,许多未完成的异步操作可能随时都在进行中。它可能是也可能不是多线程的。
默认情况下,await
会将继续安排回“当前执行上下文”。“当前执行上下文”被定义为SynchronizationContext.Current
如果它是 non- null
,或者TaskScheduler.Current
如果没有SynchronizationContext
。
ConfigureAwait
您可以通过调用和传递参数false
来覆盖此默认行为。continueOnCapturedContext
在这种情况下,不会将继续安排回该执行上下文。这通常意味着它将在线程池线程上运行。
除非您正在编写库代码,否则默认行为正是您所期望的。WinForms、WPF 和 Silverlight(即所有 UI 框架)都提供一个SynchronizationContext
,因此继续在 UI 线程上执行(并且可以安全地访问 UI 对象)。ASP.NET 还提供了一个SynchronizationContext
确保继续在正确的请求上下文中执行的方法。
其他线程(包括线程池线程、Thread
和BackgroundWorker
)不提供SynchronizationContext
. 因此默认情况下,控制台应用程序和 Win32 服务根本没有SynchronizationContext
。在这种情况下,继续在线程池线程上执行。这就是为什么控制台应用程序演示使用await
/async
包括调用Console.ReadLine
/ReadKey
或Wait
对Task
.
如果你发现自己需要一个SynchronizationContext
,你可以AsyncContext
从我的Nito.AsyncEx库中使用;它基本上只是提供了一个async
兼容的“主循环”和一个SynchronizationContext
. 我发现它对控制台应用程序和单元测试很有用(VS2012 现在内置了对async Task
单元测试的支持)。
有关详细信息SynchronizationContext
,请参阅我的 2 月 MSDN 文章。
在任何时候都不会DoEvents
调用或等效调用;相反,控制流一直返回,而延续(函数的其余部分)计划稍后运行。这是一个更简洁的解决方案,因为它不会像DoEvents
使用时那样导致重入问题。