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

时间:2015-05-05 05:22:13

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

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

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

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

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

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

有人知道这个魔法是如何实际实现的吗? async功能是否被剥离,async是否同步等待,或者是否有一些黑魔法被CLR完成这使它能够恢复因await而产生的线程?

1 个答案:

答案 0 :(得分:7)

线程确实很快终止了。

但由于db.users.find({'_id': ObjectId('5546329a470000850084a621')}, {accounts: {$elemMatch: {_id: ObjectId('5546329a470000850084a655')}}}) 构造函数不接受Thread lambda,因此你会得到一个async代表。

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

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

ThreadPool

输出:

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();

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

Run

您可以与void Run(Action action) { action(); } 代表联系

async

Run(async () => { while(true) { await SomeLengthyTask(); ... } }); 的执行几乎会在到达第一个Run时立即完成并返回。 await代表的其余部分将继续使用另一个帖子async

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

在您的情况下,您明确创建的线程不是async的一部分,因此它肯定会被终止,其余的将在不同的线程上运行。