我刚刚测试了一些我确信会惨遭失败的东西,但令我惊讶的是,它完美无瑕地工作,并向我自己证明我对async-await
的工作方式仍然感到十分神秘。
我创建了一个线程,传递一个async void
委托作为线程的主体。
这是我的代码的过度简化:
var thread = new Thread( async () => {
while( true ) {
await SomeLengthyTask();
...
}
});
thread.Start();
thread.Join();
据我所知,当执行命中await
关键字时,会从方法中隐式返回,在这种情况下是循环线程的主体,而其余的代码包含在回调延续中。
由于这个事实,我很确定线程会在await
执行后立即终止,但事实并非如此!
有人知道这个魔法是如何实际实现的吗? async
功能是否被剥离,async
是否同步等待,或者是否有一些黑魔法被CLR完成这使它能够恢复因await
而产生的线程?
答案 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
的一部分,因此它肯定会被终止,其余的将在不同的线程上运行。