C#5异步/等待 - 是*并发*?

Nei*_*ell 57 c# continuations async-await

我一直在考虑C#5中新的异步内容,并提出了一个特别的问题.

我知道await关键字是一个简洁的编译器技巧/语法糖来实现连续传递,其中方法的其余部分被分解为Task对象并排队以按顺序运行,但是控制返回到调用方法.

我的问题是,我听说目前这一切都在一个线程上.这是否意味着这种异步内容实际上只是将连续代码转换为Task对象然后Application.DoEvents()在每个任务完成之后调用,然后再开始下一个任务?

或者我错过了什么?(问题的这一部分是修辞 - 我完全清楚我错过了什么 :))

Ste*_*ary 52

它是并发的,因为许多优秀的异步操作可能在任何时候都在进行中.它可能是也可能不是多线程的.

默认情况下,await将连续计划安排回"当前执行上下文"."当前执行上下文"被定义为SynchronizationContext.Current它是非null,或者TaskScheduler.Current如果没有SynchronizationContext.

您可以通过调用覆盖此默认行为,ConfigureAwait并通过falsecontinueOnCapturedContext参数.在这种情况下,继续将不会被安排回该执行上下文.这通常意味着它将在线程池线程上运行.

除非您正在编写库代码,否则默认行为正是您所希望的.WinForms,WPF和Silverlight(即所有UI框架)提供了一个SynchronizationContext,因此延续在UI线程上执行(并且可以安全地访问UI对象).ASP.NET还提供了一个SynchronizationContext确保继续在正确的请求上下文中执行的方法.

其他线程(包括线程池线程,ThreadBackgroundWorker)不提供SynchronizationContext.因此,默认情况下,控制台应用程序和Win32服务根本没有SynchronizationContext.在这种情况下,continuation在线程池线程上执行.这就是为什么控制台应用程序演示使用await/ async包括调用Console.ReadLine/ ReadKey或对其执行阻止Wait的原因Task.

如果您发现自己需要SynchronizationContext,可以使用AsyncContext我的Nito.AsyncEx库; 它基本上只提供了一个async兼容的"主循环" SynchronizationContext.我发现它对Console应用程序和单元测试很有用(VS2012现在内置了对async Task单元测试的支持).

有关的更多信息SynchronizationContext,请参阅我的2月MSDN文章.

在任何时候都不是DoEvents或等同的; 相反,控制流一直返回,并且延续(函数的其余部分)计划在以后运行.这是一个更清洁的解决方案,因为它不会像DoEvents使用时那样导致重入问题.


Pol*_*ial 5

async/await背后的整个想法是它很好地执行continuation传递,并且不为该操作分配新线程.继续可能在新线程上发生,它可能在同一线程上继续.

  • 啊好吧 我认为这是我在很长一段时间内看到的最不透明的黑盒功能之一.这是你不能作弊的事情之一 - 你真的需要很好地理解它是如何工作的,以便使用它(或者在我的情况下,甚至理解它). (4认同)
  • 因此,它是否进行了优化,以确保来自 UI 线程的调用被编组回该线程以返回值,或者一旦使用“async”关键字,所有的赌注都会消失? (2认同)
  • 呃不,当然......说真的,有些东西可以让你侥幸逃脱,至少一段时间.我敢打赌,有很多C#开发人员不了解字符串实习或者在某些情况下为什么`ReaderWriterLockSlim`比`Monitor`更好.更多人知道如何驾驶他们的汽车,但如果它破裂就无法修理它.我碰巧认为这是你不能真正利用它,直到你先搞砸它. (2认同)