问题描述
我是否正确地认为 async/await 本身与并发/并行无关,只不过是延续传递风格 (CPS) 实现?而真正的线程是由await
传递/恢复的SynchronizationContext
实例执行的?
Am I correct that async/await itself has nothing to do with concurrency/parallelism and is nothing more than continuation-passing style (CPS) implementation? And the real threading is performed by SynchronizationContext
instance that await
passes/restores?
如果这是正确的,我有以下关于 SynchronizationContext
的问题:
它保证将在同一线程上执行延续.
If that is correct I have the following question about SynchronizationContext
:
it guarantees that a continuation will be executed on the same thread.
然而,是否有任何保证线程的上下文信息被持久化?我的意思是 Name
、CurrentPrincipal
、CurrentCulture
、CurrentUICulture
等等.它是否依赖于框架(ASP.NET、WinForms、WCF、WPF)?
However, are there any guaranties that the thread's context information is persisted? I mean Name
, CurrentPrincipal
, CurrentCulture
, CurrentUICulture
, etc. Does it depend on framework (ASP.NET, WinForms, WCF, WPF)?
推荐答案
嗯,async
/await
是使用CPS的重写,所以你的核心理解是正确的.
Well, async
/ await
is a rewriting that uses CPS, so your core understanding is correct.
关于并发"和并行",我会说它确实支持并发;您可以同时启动多个 async
操作,这些操作都在进行中".使用 Task.WhenAll
和 Task.WhenAny
很容易做到这一点.
Regarding "concurrency" and "parallelism", I would say that it does enable concurrency; you can start multiple async
operations which are all "in flight" at the same time. This is easy to do with Task.WhenAll
and Task.WhenAny
.
此外,即使 async
本身并不意味着多线程",Task.Run
确实支持简单的 async
兼容多线程
Also, even though async
by itself doesn't imply "multithreading", Task.Run
does enable easy async
-compatible multithreading
而真正的线程是由等待传递/恢复的 SynchronizationContext 实例执行的?
这样想:CPS 重写创建的延续必须在某处运行.捕获的异步上下文"可用于安排延续.
Think of it this way: the continuation created by the CPS rewriting has to run somewhere. The captured "async context" can be used to schedule the continuation.
旁注:捕获的上下文实际上是 SynchronizationContext.Current
除非它为 null,在这种情况下捕获的上下文是 TaskScheduler.Current
.
Side note: the captured context is actually SynchronizationContext.Current
unless it is null, in which case the captured context is TaskScheduler.Current
.
另一个重要的注意事项:上下文的捕获和恢复实际上取决于等待者"对象.因此,默认情况下,如果您 await
一个 Task
(或任何其他内置的 awaitable),上下文将被捕获和恢复.但是如果你await
ConfigureAwait(false)
的结果,那么上下文就不会被捕获.类似地,如果您await
您自己的自定义等待,它不会捕获上下文(除非您对其进行编程).
Another important note: the capturing and restoring of the context is actually up to the "awaiter" object. So, by default, if you await
a Task
(or any other built-in awaitable), the context will be captured and restored. But if you await
the result of ConfigureAwait(false)
, then the context is not captured. Similarly, if you await
your own custom awaitable, it won't capture the context (unless you program it to).
然而,是否有任何保证线程的上下文信息被持久化?我的意思是名称、CurrentPrincipal、CurrentCulture、CurrentUICulture 等
SynchronizationContext
与 ExecutionContext
不同.一个简单的答案是 ExecutionContext
总是流动",所以 CurrentPrincipal
流动(如果没有,它可能是一个安全问题,这就是为什么不flow ExecutionContext
总是以 Unsafe
结尾.
SynchronizationContext
is different than ExecutionContext
. A simplified answer is that ExecutionContext
always "flows", so CurrentPrincipal
flows (if it didn't, it could be a security issue, which is why APIs that don't flow ExecutionContext
always end in Unsafe
).
在 UI 应用程序中,文化不会流动,但默认情况下,所有线程都一样.Name
绝对不会流动,除非你在同一个线程上恢复(例如,使用 UI SynchronizationContext
).
In UI apps, culture doesn't flow, but by default it's the same for all threads anyway. Name
is definitely not going to flow, unless you resume on the same thread (e.g., using a UI SynchronizationContext
).
为了进一步阅读,我建议从我自己的 async
开始/await
教程,然后是 官方async
/await
FAQ.那就看看Stephen Toub关于ExecutionContext的博文
vs. SynchronizationContext
.
For some further reading, I recommend starting with my own async
/ await
tutorial and then the official async
/ await
FAQ. Then take a look at Stephen Toub's blog post on ExecutionContext
vs. SynchronizationContext
.
您可能还会发现我的SynchronizationContext
文章很有帮助.
You may also find my SynchronizationContext
article helpful.
这篇关于理解 C# 5 async/await 中的上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!