哪个线程在“await”关键字之后运行代码
本文关键字:关键字 之后 运行 代码 await 线程 | 更新日期: 2023-09-27 18:36:29
让我发布一个简单的例子:
private void MyMethod()
{
Task task = MyAsyncMethod();
task.Wait();
}
private async Task MyAsyncMethod()
{
//Code before await
await MyOtherAsyncMethod();
//Code after await
}
假设我在单线程应用程序(如控制台应用程序)中运行上述代码。我很难理解代码//Code after await
如何运行。
我知道当我在控件中点击 await
关键字时MyAsyncMethod()
会回到MyMethod()
,但随后我用 task.Wait()
锁定线程。如果线程被锁定,如果应该占用它的线程被锁定,//Code after await
怎么能运行?
是否创建新线程以运行//Code after await
?还是主线程神奇地跳出task.Wait()
运行//Code after await
?
我不确定这应该如何工作?
从主线程调用,发布的代码将在Winform应用程序中"死锁",因为您正在使用Wait()
阻塞主线程。
但是在控制台应用程序中,这有效。 但是怎么做呢?
答案隐藏在SynchronizationContext.Current
. await
捕获"同步上下文",当任务完成时,它将在相同的"同步上下文"中继续。
在winform 应用程序中,SynchronizationContext.Current
将设置为WindowsFormsSynchronizationContext
哪个将发布到对"消息循环"的调用,但是谁将处理它? 出主线程正在等待Wait()
。
在控制台应用中,默认情况下不会设置SynchronizationContext.Current
,因此当没有"同步上下文"可供 await 捕获时,它将null
,因此它将计划继续ThreadPool
(TaskScheduler.Default 这是 ThreadpoolTaskScheduler),因此 await 之后的代码有效(通过线程池线程)。
可以使用Task.ConfigureAwait(false);
来控制上述捕获行为,这将防止wform应用程序死锁,但await
后的代码不再在UI线程中运行。
是否创建一个新线程以在等待后运行//Code?
或。也许不是。Task
的可等待模式实现使用同步上下文运行延续(await
表达式之后的位),该上下文在 await 表达式开始时为"当前"。例如,如果你在 UI 线程的上下文中,这意味着你最终将返回到同一个 UI 线程。如果你在线程池线程中,你最终会回到某个线程池线程上,但它可能是另一个线程。
当然,对于代码示例,如果你在 UI 线程中,则对 Wait()
的调用将阻止 UI 线程,以便延续无法运行 - 你需要小心这一点。(调用 Wait()
或 Result
来处理您不知道已完成的任务,并且可能需要在当前线程上工作,这是一个坏主意。
请注意,您可以调用Task.ConfigureAwait
以便表达不需要在同一上下文中继续的意图。这通常适用于不关心它们在哪个线程上运行的库方法:
await task.ConfigureAwait(false);
(它影响的不仅仅是线程 - 它是捕获或不捕获的整个上下文。
我认为通过等待熟悉引擎盖下发生的事情是个好主意。网上有很多文档,如果你允许我一个简短的插件,还有 C# 深入的第 3 版,以及我关于该主题的 Tekpub 截屏视频系列。或者从 MSDN 开始,然后从那里继续。