异步和同步上下文

本文关键字:上下文 同步 异步 | 更新日期: 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(((,不会发生真正的并行性。我明白了吗 正确?

只有当我们谈论并行性时,才必须涉及线程。您的示例是关于并发的

让我们分解一下:

  1. 你执行PrintAnswerToLife,它又GetAnswerToLife运行,然后它就在那里击中了Task.Delay(5000)的第一个await。一旦命中,返回会将控制权交还给PrintAnswerToLife,然后返回Task<int>本身将await返回,这将导致执行让回Go。同时,开始执行对PrintAnswerToLife的第二次调用

  2. task2执行相同的循环。

  3. 然后按顺序await每个Task。您可以使用Task.WhenAll轻松地同时等待它们。

阿尔巴哈里这是什么意思?我不明白如何 同步上下文在这里发挥作用,它有什么区别 做?

SynchronizationContext负责您的执行流程。在.NET中,我们有各种SynchronizationContext,例如DispatcherSynchronizationContextWinFormSynchronizationContext,它们负责将工作封送回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使用无法并行执行任何内容的单个线程。