哪个线程在“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

我不确定这应该如何工作?

哪个线程在“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 开始,然后从那里继续。