等待创建另一个线程吗?

时间:2019-04-08 19:10:47

标签: c# .net async-await

我阅读了Microsoft document有关异步和等待的信息。它说:

  

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

但是我运行下面的代码

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain
    {
        static void Main()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            Task task = Test();
            task.Wait();
        }

        public async static Task Test()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            await Task.Delay(1000);
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

    }
}

结果是

  

1
  1
  4

很明显

await Task.Delay(1000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

在另一个线程中运行。为什么文档说没有创建线程?

我已经阅读了上一个问题Does the use of async/await create a new thread?,但没有回答我的问题,answer只是从Microsoft来源复制粘贴。为什么在测试中看到不同的线程ID?

3 个答案:

答案 0 :(得分:8)

我总是鼓励人们阅读我的async intro,并跟进async best practices。总结:

await默认情况下会捕获一个“上下文”,并在该上下文中恢复执行async方法。在这种情况下,上下文是线程池上下文。因此,这就是为什么您看到Test恢复在线程池线程上执行的原因。

asyncawait本身不会创建任何其他线程;例如,如果您在UI应用程序中执行相同的操作,则“上下文”将是UI线程,而Test将继续在该UI线程上执行。但是await隐式捕获的上下文是调度asnc连续的原因,在此示例中,上下文只是将其调度到线程池中。

答案 1 :(得分:0)

您在测试中看到了不同的线程ID,因为使用了不同的线程来执行代码。这并不意味着异步/等待导致了其他线程的创建。在这种情况下,使用的线程已经存在于称为线程池的线程池中。

有两个不同的想法:

  • 代表要完成工作的任务,
  • 任务的实际处理方式(例如计划和执行)

异步/等待与前者有关,但是您的测试代码告诉您有关后者的信息:处理这些任务的特定机制。

该机制由上下文决定。一些上下文使用多个线程(但是请注意,上下文取决于它如何管理这些线程,包括是否以及何时创建新线程),但某些上下文仅使用1个线程。

使用了一个以上的线程是与上下文有关,而不是异步/等待。

答案 2 :(得分:-2)

我稍微改变了你的例子:

Nothing :: Maybe Integer

现在输出为1、1、1。

public async static Task Test() { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); await Task.CompletedTask; // <--- instead of Task.Delay() Console.WriteLine(Thread.CurrentThread.ManagedThreadId); } 未创建新线程。 await是元凶!