异步线程体循环,它只是工作,但如何?

Blu*_*rat 7 .net c# multithreading asynchronous async-await

我刚刚测试了一些我确信会失败的东西,但令我惊讶的是,它完美无瑕地工作,并向我自己证明我仍然对async-await工作的方式感到很困惑.

我创建了一个线程,将async void委托作为线程的主体传递.这是我的代码过度简化:

var thread = new Thread( async () => {
   while( true ) {
      await SomeLengthyTask();
      ...
   }
});
thread.Start();
thread.Join();
Run Code Online (Sandbox Code Playgroud)

问题是,据我所知,当执行命中await关键字时,从方法中隐式返回,在这种情况下是循环线程的主体,而其余代码包含在回调延续中.

由于这个事实,我很确定线程会在await产生执行后立即终止,但事实并非如此!

有谁知道这个魔法是如何实际实现的?async功能精简和async同步等待或者是有一些黑魔法将使它能够恢复已因为一次产生一个线程CLR正在做await

i3a*_*non 7

线程确实很快终止了.

但是由于Thread构造函数不接受asynclambda你得到的是一个async void委托.

原始线程将结束,并且继续(后面的其余部分await)将被发布到ThreadPool并最终在另一个线程上运行.

您可以通过检查线程ID来测试它:

var thread = new Thread(async () =>
{
    while (true)
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        await SomeLengthyTask();
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    }
});
thread.Start();
thread.Join();

Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)

输出:

3
5
5
...
5
Run Code Online (Sandbox Code Playgroud)

为了使示例更简单,我们假设您使用此Run方法:

void Run(Action action)
{
    action();
}
Run Code Online (Sandbox Code Playgroud)

你和你的async代表打电话给你

Run(async () => 
{
    while(true) 
    {
      await SomeLengthyTask();
      ...
    }
});
Run Code Online (Sandbox Code Playgroud)

Run当它到达第一个await并返回时,执行将几乎立即完成.async委托的其余部分将继续ThreadPool使用另一个线程.


通常,每次await在执行某个async方法时,线程都会丢失,并且继续(等待任务完成后的其余部分)将被发布到ThreadPool(除非存在SynchronizationContext,如UI线程中).可能是它执行将在同一个线程上(如我的例子中的5)但它也可能不会.

在你的情况下,你明确创建的线程不是它的一部分ThreadPool所以它肯定会被终止,其余的将在不同的线程上运行.

  • @BlueStrat不,它确实发生了.这就是为什么我在我的例子中添加了一个`Console.ReadLine`.没有它我的控制台应用程序在到达有趣的部分之前结束 (2认同)