异步和同步上下文
本文关键字:上下文 同步 异步 | 更新日期: 2023-09-27 18:26:15
请考虑以下代码:
async Task Go()
{
var task1 = PrintAnswerToLife();
var task2 = PrintAnswerToLife();
await task1; await task2;
}
async Task PrintAnswerToLife()
{
var task = GetAnswerToLife();
int answer = await task; Console.WriteLine(answer);
}
async Task<int> GetAnswerToLife()
{
var task = Task.Delay(5000);
await task; int answer = 21 * 2; return answer
}
问题1:
在Albahari兄弟的">简而言之的C# 5.0"一书的第14章第588页中,指出两个异步操作task1和task2并行运行。这在我看来是不正确的。据我了解,当var task1 = PrintAnswerToLife();
运行时,执行进入PrintAnswerToLife()
,当它命中时await
将执行返回到Go()
,并继续到下一行var task1 = PrintAnswerToLife();
,同样的事情再次发生。换句话说,在Go()
的前两行中没有并行发生任何内容。事实上,除非涉及线程(如Task.Run()
或Task.Delay()
(,否则不会发生真正的并行性。我理解正确吗?如果是这样,阿尔巴哈里说这两个行动并行进行到底是什么意思?
问题2:
在同一页上,Albahari继续陈述以下内容:
以这种方式创建的并发性发生,无论 操作是在 UI 线程上启动的,尽管存在 它发生方式的不同。在这两种情况下,我们得到相同的 在启动它的底层操作中发生的并发 (例如 Task.Delay,或创建到 Task.Run 的代码(。以上方法 在调用堆栈中,仅当 操作在不存在同步上下文的情况下启动...
阿尔巴哈里这是什么意思?我不明白SynchronizationContext
在这里是如何发挥作用的,它有什么区别。
事实上,除非涉及线程(如 Task.Run(( 或 Task.Delay(((,不会发生真正的并行性。我明白了吗 正确?
只有当我们谈论并行性时,才必须涉及线程。您的示例是关于并发的
让我们分解一下:
-
你执行
PrintAnswerToLife
,它又GetAnswerToLife
运行,然后它就在那里击中了Task.Delay(5000)
的第一个await
。一旦命中,返回会将控制权交还给PrintAnswerToLife
,然后返回Task<int>
本身将await
返回,这将导致执行让回Go
。同时,开始执行对PrintAnswerToLife
的第二次调用
对 task2
执行相同的循环。然后按顺序
await
每个Task
。您可以使用Task.WhenAll
轻松地同时等待它们。
阿尔巴哈里这是什么意思?我不明白如何 同步上下文在这里发挥作用,它有什么区别 做?
SynchronizationContext
负责您的执行流程。在.NET中,我们有各种SynchronizationContext
,例如DispatcherSynchronizationContext
和WinFormSynchronizationContext
,它们负责将工作封送回UI线程(分别为WPF和WinForms(。我认为他想指出的是,这些SynchronizationContext
中的每一个最终都会将控制权编组回某种 UI 消息循环,该循环将被迫一个接一个地同步执行。如果没有SynchronizationContext
,则默认使用ThreadPoolSynchronizationContext
,这将在任意线程池线程上调用这些任务的延续。这并不完全正确,因为可以使用 ConfigureAwait(false)
避免将上下文封送回 UI 线程。
问题 1:
并行通常意味着多个线程同时处理。此处使用的更准确的术语是并发。在您的示例中,两个任务同时执行。这意味着异步操作(即 await Task.Delay(5000)
( 在两个任务中同时"执行"。这就是为什么这两个任务都会在Go
开始后大约 5 秒内完成。如果任务按顺序运行,则需要 10 秒。然后,同步延续将被安排在线程池线程上(假设没有特殊SynchronizationContext
(,并且
我理解正确吗?
是的。
如果是这样,阿尔巴哈里说这两个行动并行进行到底是什么意思?
它们与潜在的并行延续同时异步运行。
问题2:
同样,解释有点简单。它指的是特定的SynchronizationContext
,即GUI环境中使用的单线程SynchronizationContext
。由于此SynchronizationContext
将所有工作安排在单个特定线程上,因此不允许"真正的并发"。但是,还有其他多线程SynchronizationContext
,您可以创建自己的多线程。因此,使用 SynchronizationContext
不一定会妨碍并发性(您也可以通过在任务上使用 ConfigureAwait(false)
来完全禁用SynchronizationContext
捕获(
阿尔巴哈里这是什么意思?
在 GUI 环境中,SynchronizationContext
使用无法并行执行任何内容的单个线程。