async和await关键字不会导致创建其他线程吗?

max*_*oin 27 c# multithreading conceptual task-parallel-library async-await

我糊涂了.一个或多个如何Task在一个线程上并行运行?我对并行性的理解显然是错误的.

MSDN的比特我无法理解:

async和await关键字不会导致创建其他线程.异步方法不需要多线程,因为异步方法不能在自己的线程上运行.该方法在当前同步上下文上运行,并仅在方法处于活动状态时在线程上使用时间.

..和:

在启动任务和等待任务之间,您可以启动其他任务.其他任务隐式并行运行,但不会创建其他线程.

Ben*_*igt 24

它们并不是并行运行,而是轮流运行.当正在运行的任务阻止进度时,它会将其状态和控制权存储到就绪任务中.这是合作的多任务处理,而不是真正的并行性.

线程根据样本原理运行.但是,我想强调几个关键的区别.

首先,仅仅因为async/ await不是OS线程:

  • 任务不会看到不同的线程ID
  • 当任务产生时,线程本地存储不会自动上下文切换.

其次,行为的差异:

  • async/ await使用合作多任务,Win32线程使用抢先.因此,所有阻塞操作必须使用async/ awaitmodel 显式地产生控制.因此,您可以通过对未编写为yield的函数进行阻塞调用来阻止整个线程及其所有任务.
  • 任务不会在多处理系统上并行执行.由于重新引入被控制,这使得保持数据结构一致性变得更加容易.

正如Stephen在评论中指出的那样,如果使用多线程同步上下文,则可以在多个OS线程中同时执行(以及所有复杂性和潜在的竞争条件).但是MSDN引用是关于单线程上下文的情况.

最后,在其他地方使用此相同的设计模式,你可以学到很多好的做法async/ await通过研究这些:

  • Win32 Fibers(使用与线程相同的调用样式,但是合作)
  • Win32 重叠I/O操作,Linux aio
  • 协同程序

  • @BenVoigt:许多更新的答案仅适用于在单线程`SynchronizationContext`(例如UI上下文)中执行的`async`方法.如果它们在控制台应用程序或后台线程中运行,则`task`s将在线程池上执行,*将*并行执行(在多个线程上),除非您单独"等待"每个线程. (4认同)
  • +1.请注意,`async`方法在`await`*上阻塞*时保存其状态和产量.如果它正在运行阻塞代码(如`Thread.Sleep`),那么它将不会保存其状态和产量. (3认同)