是否使用async/await创建一个新线程?

dev*_*hog 40 c# multithreading task-parallel-library async-await c#-5.0

我是TPL的新手,我想知道:C#5.0中新增的异步编程支持(通过new asyncawait关键字)如何与线程的创建有关?

具体来说,async/await每次使用它们时是否使用创建新线程?如果有许多嵌套方法使用async/await,是否为每个方法创建了一个新线程?

Adr*_*der 45

总之NO

Async和Await的异步编程:线程

async和await关键字不会导致创建其他线程.异步方法不需要多线程,因为异步方法不能在自己的线程上运行.该方法在当前同步上下文上运行,并仅在方法处于活动状态时在线程上使用时间.您可以使用Task.Run将CPU绑定的工作移动到后台线程,但后台线程无助于正在等待结果可用的进程.

  • 无论我多少次看这个问题,我仍然不明白."异步方法不需要多线程,因为异步方法不能在自己的线程上运行"Ergo - >另一个线程.怎么会这样呢? (9认同)
  • 并非每个操作都需要一个线程.典型系统上有许多处理器/控制器,包括磁盘控制器,网卡控制器,GPU等.它们只需要从处理器接收命令.然后他们继续执行命令并在完成时告诉处理器(通过中断它或其他一些机制来通知它).在那之前,没有线程涉及.发布线程可以进入休眠状态,也可以转到可以重用的线程池.当命令完成时,睡眠线程或线程池线程可以继续执行程序. (9认同)
  • @dudeNumber4"异步方法不会在它自己的线程上运行 - > ergo另一个线程".不,它在同一个线程上运行!与调用它的方法相同的线程.它只是返回到该调用方法,以防它开始"等待"某些东西,以免浪费CPU周期. (4认同)

Elo*_*Elo 16

根据 MSDN :async 关键字

异步方法同步运行,直到它到达它的第一个 await 表达式,此时该方法将挂起,直到等待的任务完成。同时,控制权返回给方法的调用者,如下一节中的示例所示。

这是检查它的示例代码:

class Program

{
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }

    private void Print(string txt)
    {
        string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
        Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
    }

    private void Run()
    {
        Print("Program Start");
        Experiment().Wait();
        Print("Program End. Press any key to quit");
        Console.Read();
    }

    private async Task Experiment()
    {
        Print("Experiment code is synchronous before await");
        await Task.Delay(500);
        Print("Experiment code is asynchronous after first await");
    }
}
Run Code Online (Sandbox Code Playgroud)

结果: 实验结果:await后的代码在另一个线程中执行

我们在另一个 Thread 上执行 await 后看到 Experiment() 方法的代码。

但是如果我用我自己的代码(方法SomethingElse)替换Task.Delay:

   class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        p.Run();
    }

    private void Print(string txt)
    {
        string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
        Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
    }

    private void Run()
    {
        Print("Program Start");
        Experiment().Wait();
        Print("Program End. Press any key to quit");
        Console.Read();
    }

    private async Task Experiment()
    {
        Print("Experiment code is synchronous before await");
        await SomethingElse();
        Print("Experiment code is asynchronous after first await");
    }

    private Task SomethingElse()
    {
        Print("Experiment code is asynchronous after first await");
        Thread.Sleep(500);
        return (Task.CompletedTask);
    }
}
Run Code Online (Sandbox Code Playgroud)

我注意到线程保持不变!

即使使用 async/await 线程也是一样的

总之,我会说 async/await 代码可以使用另一个线程,但前提是该线程是由另一个代码创建的,而不是由 async/await 创建的。

在这种情况下,我认为Task.Delay创建了线程,所以我可以得出结论 async/await 不会像@Adriaan Stander 所说的那样创建新线程。

  • 谢谢你。我认为它澄清了由于 Async Await 经常与 TAP(任务异步模式)中的任务一起使用这一事实而引起的一些混乱。因此,有些人错误地认为 Async Await 创建一个新线程而不是 Task。据我了解,TAP 模式提供了一种更干净地管理多线程功能的方法。 (4认同)

Vib*_*nRC 5

很抱歉在聚会上迟到了。

我是 TPL 的新手,我想知道:C# 5.0 的新异步编程支持(通过新的 async 和 await 关键字)与线程的创建有何关系?

async/await 不是为了创建线程而引入的,而是为了最佳地利用当前线程。

您的应用程序可能会读取文件、等待来自另一台服务器的响应,甚至执行具有高内存访问权限的计算(任何 IO 任务)。这些任务不是 CPU 密集型的(任何不会使用 100% 线程的任务)。

考虑一下您正在处理 1000 个非 CPU 密集型任务的情况。在这种情况下,创建 1000 个操作系统级线程的过程可能比在单个线程上执行实际工作消耗更多的 CPU 和内存(Windows 中每个线程 4mb,4MB * 1000 = 4GB)。同时,如果您按顺序运行所有任务,则可能必须等到 IO 任务完成。这最终会在很长的时间内完成任务,同时保持 CPU 空闲。

由于我们需要并行性来快速完成多个任务,同时所有并行任务都不会占用 CPU,但创建线程效率低下。

编译器将在对方法的任何方法调用async(通过 await调用)时中断执行,并立即执行当前代码分支之外的代码,一旦await到达,执行将进入前一个async. 这将一次又一次地重复,直到所有异步调用完成并awaiters得到满足。

如果任何异步方法在没有调用异步方法的情况下具有沉重的 CPU 负载,那么是的,您的系统将变得无响应,并且在当前任务完成之前不会调用所有剩余的异步方法。