【问题标题】:The async and await keywords don't cause additional threads to be created?async 和 await 关键字不会导致创建额外的线程?
【发布时间】:2012-12-21 16:29:38
【问题描述】:

我很困惑。一个或多个Task 如何在单个线程上并行运行?我对并行性的理解显然是错误的。

我无法理解的 MSDN 内容:

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

.. 和:

在开始任务和等待它之间,您可以开始其他任务。 额外的任务隐式地并行运行,但没有额外的 线程已创建。

【问题讨论】:

    标签: c# multithreading task-parallel-library async-await conceptual


    【解决方案1】:

    它们不是并行运行,而是轮流运行。当正在运行的任务的进度被阻止时,它会存储其状态并将控制权交给就绪的任务。这是协作多任务,而不是真正的并行。

    线程按照示例原理运行。不过,我想强调几个关键区别。

    首先,仅仅因为async/await 不是操作系统线程:

    • 任务不会看到不同的线程 ID
    • 当任务屈服时,线程本地存储不会自动进行上下文切换。

    其次,行为上的差异:

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

    正如斯蒂芬在评论中指出的那样,如果您使用多线程同步上下文,您可以在多个操作系统线程中同时执行(以及所有复杂性和潜在的竞争条件)。但是 MSDN 的引用是关于单线程上下文案例的。

    最后,在其他地方也使用了相同的设计范式,您可以通过研究这些来了解async/await 的良好实践:

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

    【讨论】:

    • “阻塞”在这里使用可能是一个令人困惑的术语,因为异步的目标是避免阻塞。
    • +1。请注意,async 方法会保存其状态并在它被 await 阻塞时产生。如果它正在运行阻塞代码(如Thread.Sleep),那么它不会保存它的状态和yield。
    • @Cory:个别任务被阻塞,线程不会(正如斯蒂芬所说,只有当你对所有事情都使用协程时才会这样)。
    • 我认为应该说清楚,为什么 MS 写这个。许多人认为,“异步”使方法异步运行(在单独的线程上)。不,它没有。而且await SomeMethodAsync() 也不会创建新线程,只是因为等待。如果 SomeMethodAsync 创建了一个新线程(它不一定会这样做),则会创建一个新线程
    • @BenVoigt:许多更新后的答案仅适用于在单线程 SynchronizationContext(例如 UI 上下文)中执行的 async 方法。如果它们在控制台应用程序或后台线程中运行,则 Tasks 将在线程池上执行并且并行执行(在多个线程上),除非您 await 每个单独.
    猜你喜欢
    • 1970-01-01
    • 2012-11-28
    • 2015-01-31
    • 2012-06-29
    • 2015-05-04
    • 2020-05-30
    • 2018-06-30
    • 1970-01-01
    相关资源
    最近更新 更多