为什么async在点击await后不将控制权返回给调用者?

问题描述 投票:0回答:1

我试图了解 async/await 在 C# 中如何工作,特别是与线程行为相关。我一直在阅读 Stephen Cleary 关于异步和等待的博客文章 (https://blog.stephencleary.com/2012/02/async-and-await.html),文档的一部分让我感到困惑:

异步方法的开头就像任何其他方法一样执行 方法。也就是说,它同步运行,直到遇到“等待”(或 抛出异常)。

我有以下代码:

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine($"Thread Id entering Main Method: {Thread.CurrentThread.ManagedThreadId}");
        await Something_One();
    }
    static async Task Something_One()
    {
        Console.WriteLine($"Thread Id entering Something_One: {Thread.CurrentThread.ManagedThreadId}");
        await Something_Two();
    } 
    
    static async Task Something_Two()
    {
        Console.WriteLine($"Thread Id Entring Something_Two: {Thread.CurrentThread.ManagedThreadId}");
        await Task.Delay(1000);
    }
}

我看到的输出是:

Thread Id entering Main Method: 1
Thread Id entering Something_One: 1
Thread Id Entring Something_Two: 1

根据文档,我希望同步执行在遇到的第一个await关键字处停止(并且可能在另一个线程上继续),这是

await Something_Two()
方法中的
Something_One
。但是,输出显示
Something_Two
也会同步执行,直到到达
await Task.Delay(1000)
线。

为什么 Something_Two 会同步执行,即使它是从 Something_One 中的等待表达式调用的?

我试图理解我所观察到的线程行为背后的基本原理,特别是根据文档声明,异步方法同步运行直到它们遇到等待。有人可以解释一下幕后发生了什么吗

c# asynchronous async-await
1个回答
0
投票

await
视觉上位于该行的左侧,因此您从逻辑上假设它首先执行。实际上它是在调用
await
后面的异步方法之后执行的。如果我们像这样重写你的例子,它可能会变得更清楚:

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine($"Thread Id entering Main Method: {Thread.CurrentThread.ManagedThreadId}");
        Task task = Something_One();
        await task;
    }
    static async Task Something_One()
    {
        Console.WriteLine($"Thread Id entering Something_One: {Thread.CurrentThread.ManagedThreadId}");
        Task task = Something_Two();
        await task;
    } 
    
    static async Task Something_Two()
    {
        Console.WriteLine($"Thread Id Entring Something_Two: {Thread.CurrentThread.ManagedThreadId}");
        Task task = Task.Delay(1000);
        await task;
    }
}

上面和你的例子一模一样。现在很明显,所有代码都将同步运行,直到等待

Task.Delay(1000)
。然后所有这些方法都会向调用者返回一个不完整的
Task
。最终,控制台应用程序的主线程将被阻塞,直到
Task.Delay(1000)
任务完成,因为这就是具有
async Main
入口点的控制台应用程序的行为方式(有关详细信息,请参阅 docs)。

© www.soinside.com 2019 - 2024. All rights reserved.