【问题标题】:async and await are single threaded Really?async 和 await 是单线程的 真的吗?
【发布时间】:2016-05-30 18:06:39
【问题描述】:

我创建了以下代码:

using System;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main()
       {
         Console.WriteLine("M Start");
         MyMethodAsync();
         Console.WriteLine("M end");
         Console.Read();
       }

     static async Task MyMethodAsync()
     {
        await Task.Yield();
        Task<int> longRunningTask = LongRunningOperationAsync();
        Console.WriteLine("M3");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine(result);
     }

       static async Task<int> LongRunningOperationAsync()  
      {
        await Task.Delay(1000);
        return 1;
      }
  }
}

输出:

M Start
M end
M3
1

这很好,但是当我查看线程分析器时,它会显示: 然后这个: 然后这个:

所以看起来我产生了线程,但来自 msdn 说:

来自使用 Async 和 Await 的异步编程:线程

async 和 await 关键字不会导致额外的线程 创建的。异步方法不需要多线程,因为异步 方法不在自己的线程上运行。该方法在当前运行 同步上下文并仅在线程上使用时间 方法处于活动状态。您可以使用 Task.Run 将 CPU 密集型工作移动到 后台线程,但后台线程对进程没有帮助 那只是在等待结果可用。

我是否遗漏或不理解某些内容? 谢谢。

【问题讨论】:

  • 它使用线程池中的现有线程,而不是创建一个
  • 这看起来像是 Visual Studio 中一个非常漂亮的窗口。很抱歉这个题外话,但哪些版本支持它?
  • Thread.CurrentThread.ManagedThreadId装饰你的输出,你可能会看到正在使用3个线程。
  • @GediminasMasaitis 我认为Parallel StacksTask 视图都添加到了VS 2013 中。它们都可以在Debug -&gt; Windows 下拉菜单下找到。
  • @DinkarThakur,与您的问题有点相关,但您可能有兴趣阅读 Stepen Cleary 的博文“There is no thread”。它深入研究了等待基于 IO 的请求时发生的情况。

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


【解决方案1】:

我在我的博客上解释了how async and await work with threads and contexts。总之,当await 需要等待异步操作完成时,它会“暂停”当前的async 方法并(默认情况下)捕获“上下文”。

当异步操作完成时,该“上下文”用于恢复async 方法。这个“上下文”是SynchronizationContext.Current,除非它是null,在这种情况下它是TaskScheduler.Current。在您的情况下,上下文最终成为线程池上下文,因此 async 方法的其余部分被发送到线程池。如果您从 UI 线程运行相同的代码,则上下文将是 UI 上下文,并且所有 async 方法将在 UI 线程上恢复。

【讨论】:

    【解决方案2】:

    async 和 await 关键字不会导致创建额外的线程。

    是的。它将 CPU 绑定或 I/O 绑定工作从进程的线程池移动到其他线程,这样它就不会在 UI 线程或当前同步上下文上执行,它不会创建新线程,这在 MSDN 描述中是什么意思.

    【讨论】:

    • 但如果所有线程都被消耗,那么它将等待。对吗?
    • 这是错误的。任务在当前同步上下文中执行。仅当您使用基于线程池的同步上下文时才使用不同的线程,否则一切都在带有队列的主线程上完成。阅读“延续传递风格”,这就是异步在底层的工作方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 2020-04-20
    • 2020-08-02
    • 1970-01-01
    相关资源
    最近更新 更多