了解C#5 async / await中的上下文

我是否正确async / await本身与并发/并行无关,只不过是继续传递样式(CPS)实现? 真正的线程是由await传递/恢复的SynchronizationContext实例执行的?

如果这是正确的,我有关于SynchronizationContext的以下问题:
它保证在同一个线程上执行延续。

但是,是否有任何保证线程的上下文信息是持久的? 我的意思是NameCurrentPrincipalCurrentCultureCurrentUICulture等。它依赖于框架(ASP.NET,WinForms,WCF,WPF)吗?

我是否正确async / await本身与并发/并行无关,只不过是CPS实现?

好吧, async / await是一个使用CPS的重写,所以你的核心理解是正确的。

关于“并发”和“并行”,我会说它确实能够实现并发性; 您可以同时启动多个async操作,这些操作都在“飞行中”。 使用Task.WhenAllTask.WhenAny很容易。

此外,尽管async本身并不意味着“multithreading”,但Task.Run确实可以实现简单的async兼容multithreading

真正的线程是由等待传递/恢复的SynchronizationContext实例执行的?

可以这样想:CPS重写创建的延续必须在某个地方运行。 捕获的“异步上下文”可用于安排继续。

附注:捕获的上下文实际上是SynchronizationContext.Current 除非它为null ,在这种情况下捕获的上下文是TaskScheduler.Current

另一个重要的注意事项:捕获和恢复上下文实际上取决于“awaiter”对象。 因此,默认情况下,如果您await Task (或任何其他内置的等待),将捕获并恢复上下文。 但是,如果await ConfigureAwait(false)的结果,则不会捕获上下文。 同样,如果您await自己的自定义等待,它将不会捕获上下文(除非您将其编程)。

但是,是否有任何保证线程的上下文信息是持久的? 我的意思是Name,CurrentPrincipal,CurrentCulture,CurrentUICulture等。

SynchronizationContextExecutionContext不同。 简化的答案是ExecutionContext始终“流动”,因此CurrentPrincipal流(如果没有,则可能是安全问题,这就是为什么不流动ExecutionContext API总是以Unsafe结尾)。

在UI应用程序中,文化不会流动,但默认情况下,所有线程都是相同的。 除非您在同一个线程上恢复(例如,使用UI SynchronizationContext ),否则Name肯定不会流动。


为了进一步阅读,我建议从我自己的async / await教程开始 ,然后是官方的async / await FAQ 。 然后看一下Stephen Toub关于ExecutionContextSynchronizationContext的博客文章 。

您还可以找到我的SynchronizationContext文章 。

不, async / await关键字与并发有关。 async / await基本上将您的方法代码包装到任务和继续中。 要查看编​​译器生成的确切转换(使用任务并行库),请反汇编一些代码段。 async / await使用的这种转换与下面的例子“相似”(但不完全相同!)

 async Task TaskOfTResult_MethodAsync() { int hours; // . . . // Return statement specifies an integer result. return hours; } // Calls to TaskOfTResult_MethodAsync Task returnedTaskTResult = TaskOfTResult_MethodAsync(); int intResult = await returnedTaskTResult; // or, in a single statement int intResult = await TaskOfTResult_MethodAsync(); 

这是近似转换为

 private int Result() { int hours; // . . . // Return statement specifies an integer result. return hours; } 

你在等待方法之外等待返回的地方

 int? hours = null; Task task = null; task = Task.Factory.StartNew(() => Result()); task.ContnueWith(cont => { // Some task completion checking... hours = task.Result; }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current); 

或者,您可以将TPL代码放入Result方法中

 private int ResultAsync() { int? hours = null; Task task = null; task = Task.Factory.StartNew(() => { int hours; // . . . // Return statement specifies an integer result. return hours; }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current); try { return task.Result; } catch (AggregateException aggEx) { // Some handler method for the agg exception. aggEx.Handle(HandleException); } } 

SynchronizationContext不保证将在async / awate代码的同一线程上执行awate 。 但是,您可以通过SynchronisationContex关键字使用TPL代码设置上下文。