C#5asynchronous/等待 – 它是*并发*?

我一直在考虑C#5中的新asynchronous的东西,并提出了一个特定的问题。

我知道await关键字是一个简洁的编译器技巧/语法糖来实现continuation的传递 ,其余的方法被分解成Task对象并排队等待运行,但是控制返回到调用方法。

我的问题是,我听说目前这一切都在一个单一的线程。 这是否意味着这种asynchronous的东西实际上只是将继续代码转换为Task对象,然后在每个任务完成之后调用Application.DoEvents() ,然后再启动下一个任务?

还是我错过了什么? (问题的这一部分是修辞 – 我完全知道我错过了什么 :))

提前谢谢了。

这意味着许多优秀的asynchronous运行可能随时在进行。 它可能是也可能不是multithreading的

默认情况下, await会将延续安排回“当前执行上下文”。 如果“当前执行上下文”是非null ,则定义为SynchronizationContext.Current如果没有SynchronizationContext ,则定义为TaskScheduler.Current

您可以通过调用ConfigureAwait并为continueOnCapturedContextparameter passingfalse来覆盖此默认行为。 在这种情况下,延续将不会被安排回执行上下文。 这通常意味着它将在一个线程池线程上运行。

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

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

如果你发现自己需要一个SynchronizationContext ,你可以使用我的Nito.AsyncEx库中的AsyncContext ; 它基本上只是提供了一个与SynchronizationContext “主循环”。 我发现它适用于控制台应用程序和unit testing (VS2012现在已经内置了对async Taskunit testing的支持)。

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

DoEvents或相当于所谓的“ 相反,控制stream完全返回 ,而延续(函数的其余部分)计划稍后运行。 这是一个更清洁的解决scheme,因为它不会像使用DoEvents那样会导致重入问题。

async / await背后的全部思想是,它很好地执行continuation,并且不为操作分配一个新的线程。 继续可能发生在一个新的线程,它可能会继续在同一个线程。

asynchronous/等待的真正“肉”(asynchronous)部分通常是单独完成的,并且与调用者的通信通过TaskCompletionSource完成。 如此处所写:http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx

TaskCompletionSourcetypes提供了两个相关的用途,都是通过名称来提及的:它是创build任务的来源,以及该任务完成的来源。 本质上,TaskCompletionSource充当Task的生产者及其完成。

这个例子很明显:

 public static Task<T> RunAsync<T>(Func<T> function) { if (function == null) throw new ArgumentNullException(“function”); var tcs = new TaskCompletionSource<T>(); ThreadPool.QueueUserWorkItem(_ => { try { T result = function(); tcs.SetResult(result); } catch(Exception exc) { tcs.SetException(exc); } }); return tcs.Task; } 

通过TaskCompletionSource您可以访问可以等待的Task对象,但不是通过创buildmultithreading的async / await关键字。

请注意,当许多“慢”function将被转换为asynchronous/等待语法时,您将不需要非常多地使用TaskCompletionSource 。 他们将在内部使用它(但最终必须有一个TaskCompletionSource有一个asynchronous的结果)

我喜欢解释它的方式是,“await”关键字只是等待一个任务完成,但在等待的时候执行到调用线程。 然后它返回任务的结果,并在任务完成后从“await”关键字之后的语句继续。

我注意到一些人似乎认为任务是在与调用线程相同的线程中运行,这是不正确的,可以通过尝试更改等待调用的方法中的Windows.Forms GUI元素来certificate。 但是,继续在可能的调用线程中运行。

它只是一个完美的方式,无需为任务完成时的callback委托或事件处理程序。