异步和同步上下文

时间:2014-10-12 16:36:41

标签: c# .net multithreading asynchronous async-await

请考虑以下代码:

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:

在第488页的第14章中,#34; C#5.0 in a Nutshell &#34;由Albahari兄弟声明,两个异步操作task1和task2并行运行。这对我来说似乎不正确。据我所知,当var task1 = PrintAnswerToLife();运行时,执行进入PrintAnswerToLife(),当命中await时,执行返回Go(),然后进入下一行{{1} ,同样的事情又发生了。换句话说,在var task1 = PrintAnswerToLife();的前两行中没有任何并行发生。实际上,除非涉及一个线程(如Go()Task.Run()),否则不会发生真正的并行性。我理解正确吗?如果是这样,Albahari说这两个操作并行运行真正意味着什么?

问题2:

在同一页上,Albahari继续陈述以下内容:

  

无论是否以这种方式创建的并发   操作是在UI线程上启动的,尽管有一个   它是如何发生的差异。在这两种情况下,我们都是一样的   并发发生在启动它的底层操作中   (例如Task.Delay,或者运行到Task.Run的代码)。上面的方法   在调用堆栈中只有在真正的并发时才会受到   在没有同步上下文的情况下启动操作......

阿尔巴哈里的意思是什么?我不明白Task.Delay()如何在这里发挥作用,以及它有何不同。

2 个答案:

答案 0 :(得分:4)

  

实际上,除非涉及一个线程(如在Task.Run()或中   Task.Delay()),没有真正的并行性发生。我明白了吗   正确?

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

让我们分解:

  1. 您执行PrintAnswerToLife,而GetAnswerToLife依次运行await,然后就会Task.Delay(5000)点击PrintAnswerToLife。一旦点击,返回将使控制权返回await,然后Task<int>将返回Go,这将导致执行返回PrintAnswerToLife。同时,开始执行您对task2

  2. 的第二次通话
  3. await执行相同的循环。

  4. 然后依次Task每个Task.WhenAll。您可以使用SynchronizationContext轻松等待同时

  5.   

    阿尔巴哈里的意思是什么?我不明白怎么回事   SynchronizationContext在这里发挥作用,它有什么区别   使?

    SynchronizationContext负责执行流程。在.NET中,我们有各种DispatcherSynchronizationContext,例如WinFormSynchronizationContextSynchronizationContext,它们负责将编组工作重新分配到UI线程(分别是WPF和WinForms) )。我认为他试图指出的事实是,SynchronizationContext中的每一个最终都会将控制权归还给某种UI消息循环,这种循环将被迫一个接一个地同步执行。如果没有ThreadPoolSynchronizationContext,则使用的默认值是ConfigureAwait(false),它将在仲裁线程池线程上调用这些任务的继续。这并非完全正确,因为可以使用{{1}}避免将上下文封送回UI线程。

答案 1 :(得分:2)

问题1:

Parallel usually means multiple threads processing simultaneously. The more accurate term to use here is concurrent.在您的示例中,两个任务同时执行。这意味着两个任务中的异步操作(即await Task.Delay(5000))同时“执行”。这就是为什么两个任务在Go开始后大约5秒就完成了。如果任务按顺序运行,则需要10秒钟。然后将在线程池线程上调度同步延续(假设没有特殊的SynchronizationContext)并且存在并行机会。

  

我是否理解正确?

  

如果是这样,Albahari说这两个操作并行运行真正意味着什么?

它们与可能并行的延续并发和异步运行。

问题2:

再次解释有点过分了。 它指的是特定的SynchronizationContext s,GUI环境中使用的单线程SynchronizationContext 。因为这个SynchronizationContext调度所有工作在一个特定的线程上,所以它不允许“真正的并发”。但是,还有其他多线程SynchronizationContext,您可以创建自己的。SynchronizationContext。因此,使用SynchronizationContext不会必然阻碍并发(并且您还可以通过在任务上使用ConfigureAwait(false)来完全禁用SynchronizationContext捕获)

  

Albahari对此有何意义?

在GUI环境中,{{1}}使用一个不能并行执行任何操作的线程。