异步线程体循环,它只是工作,但如何?
Async thread body loop, It just works, but how?
我刚刚测试了一些我确信会惨败的东西,但令我惊讶的是,它完美地工作,并向我自己证明我仍然对 async-await
的工作方式感到困惑。
我创建了一个线程,传递了一个 async void
委托作为线程的主体。
这是我的代码的过度简化:
var thread = new Thread( async () => {
while( true ) {
await SomeLengthyTask();
...
}
});
thread.Start();
thread.Join();
据我所知,当执行遇到 await
关键字时,方法中有一个隐含的 return,在这种情况下是循环线程的主体,而其余代码包含在回调延续中。
由于这个事实,我很确定线程会在 await
产生执行后立即终止,但事实并非如此!
有人知道这个魔法是如何实现的吗? 是 async
功能被剥离并且 async
同步等待还是有一些黑魔法由 CLR 完成,使其能够恢复因 await
而产生的线程?
线程确实很快就终止了。
但是由于 Thread
构造函数不接受 async
lambda,所以你得到的是一个 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();
输出:
3
5
5
...
5
为了使示例更简单,我们假设您有此 Run
方法:
void Run(Action action)
{
action();
}
你用你的 async
代表
调用它
Run(async () =>
{
while(true)
{
await SomeLengthyTask();
...
}
});
Run
的执行将在到达第一个 await
和 returns 时几乎立即完成。 async
委托的其余部分将在 ThreadPool
上与另一个线程继续。
通常,每次执行 async
方法时达到 await
时,线程就会丢失,并且继续(等待任务完成后的其余部分)将发布到 ThreadPool (除非存在 SynchronizationContext,例如在 UI 线程中)。它可能会在同一个线程上执行(如我的示例中的 5),但也可能不会。
在您的情况下,您明确创建的线程不是 ThreadPool
的一部分,因此它肯定会被终止,其余的将 运行 在不同的线程上。
我刚刚测试了一些我确信会惨败的东西,但令我惊讶的是,它完美地工作,并向我自己证明我仍然对 async-await
的工作方式感到困惑。
我创建了一个线程,传递了一个 async void
委托作为线程的主体。
这是我的代码的过度简化:
var thread = new Thread( async () => {
while( true ) {
await SomeLengthyTask();
...
}
});
thread.Start();
thread.Join();
据我所知,当执行遇到 await
关键字时,方法中有一个隐含的 return,在这种情况下是循环线程的主体,而其余代码包含在回调延续中。
由于这个事实,我很确定线程会在 await
产生执行后立即终止,但事实并非如此!
有人知道这个魔法是如何实现的吗? 是 async
功能被剥离并且 async
同步等待还是有一些黑魔法由 CLR 完成,使其能够恢复因 await
而产生的线程?
线程确实很快就终止了。
但是由于 Thread
构造函数不接受 async
lambda,所以你得到的是一个 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();
输出:
3
5
5
...
5
为了使示例更简单,我们假设您有此 Run
方法:
void Run(Action action)
{
action();
}
你用你的 async
代表
Run(async () =>
{
while(true)
{
await SomeLengthyTask();
...
}
});
Run
的执行将在到达第一个 await
和 returns 时几乎立即完成。 async
委托的其余部分将在 ThreadPool
上与另一个线程继续。
通常,每次执行 async
方法时达到 await
时,线程就会丢失,并且继续(等待任务完成后的其余部分)将发布到 ThreadPool (除非存在 SynchronizationContext,例如在 UI 线程中)。它可能会在同一个线程上执行(如我的示例中的 5),但也可能不会。
在您的情况下,您明确创建的线程不是 ThreadPool
的一部分,因此它肯定会被终止,其余的将 运行 在不同的线程上。