[英]Understanding context in C# 5 async/await
我是否正确async / await本身与并发/并行无关,只不过是继续传递样式(CPS)实现? 真正的线程是由await
传递/恢复的SynchronizationContext
实例执行的?
如果这是正确的,我有关于SynchronizationContext
的以下问题:
它保证在同一个线程上执行延续。
但是,是否有任何保证线程的上下文信息是持久的? 我的意思是Name
, CurrentPrincipal
, CurrentCulture
, CurrentUICulture
等。它依赖于框架(ASP.NET,WinForms,WCF,WPF)吗?
我是否正确async / await本身与并发/并行无关,只不过是CPS实现?
好吧, async
/ await
是一个使用CPS的重写,所以你的核心理解是正确的。
关于“并发”和“并行”,我会说它确实能够实现并发性; 你可以同时启动多个async
操作,这些操作都在“飞行中”。 使用Task.WhenAll
和Task.WhenAny
很容易做到这一点。
此外,尽管async
本身并不意味着“多线程”,但Task.Run
确实可以实现简单的async
兼容多线程
真正的线程是由等待传递/恢复的SynchronizationContext实例执行的?
可以这样想:CPS重写创建的延续必须在某个地方运行。 捕获的“异步上下文”可用于安排继续。
附注:捕获的上下文实际上是SynchronizationContext.Current
除非它为null ,在这种情况下捕获的上下文是TaskScheduler.Current
。
另一个重要的注意事项:上下文的捕获和恢复实际上取决于“awaiter”对象。 因此,默认情况下,如果您await
Task
(或任何其他内置的等待),将捕获并恢复上下文。 但是,如果await
ConfigureAwait(false)
的结果,则不会捕获上下文。 同样,如果您await
自己的自定义等待,它将不会捕获上下文(除非您将其编程)。
但是,是否有任何保证线程的上下文信息是持久的? 我的意思是Name,CurrentPrincipal,CurrentCulture,CurrentUICulture等。
SynchronizationContext
与ExecutionContext
不同。 一个简单的答案是ExecutionContext
总是“流”,所以CurrentPrincipal
流(如果没有,它可能是一个安全问题,这就是为什么不流动ExecutionContext
API总是在Unsafe
结束)。
在UI应用程序中,文化不会流动,但默认情况下,所有线程都是相同的。 除非您在同一个线程上恢复(例如,使用UI SynchronizationContext
),否则Name
肯定不会流动。
为了进一步阅读,我建议从我自己的async
/ await
教程开始 ,然后是官方的async
/ await
FAQ 。 然后看看Stephen Toub关于ExecutionContext
与SynchronizationContext
的博客文章 。
您可能还会发现我的SynchronizationContext
文章很有帮助。
不, async
/ await
关键字与并发性有关。 async
/ await
基本上将您的方法代码包装到任务和继续中。 要查看编译器生成的确切转换(使用任务并行库),请反汇编一些代码段。 async
/ await
用法的这种翻译与下面的例子“相似”(但不完全相同!)
async Task<int> TaskOfTResult_MethodAsync()
{
int hours;
// . . .
// Return statement specifies an integer result.
return hours;
}
// Calls to TaskOfTResult_MethodAsync
Task<int> 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<int> task = null;
task = Task.Factory.StartNew<int>(() => 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<int> task = null;
task = Task.Factory.StartNew<int>(() =>
{
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
。 但是,您可以使用TPL代码通过SynchronisationContex
关键字设置上下文。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.