c# - 没有等待的嵌套异步方法 block

标签 c# .net asynchronous async-await

我不确定这里发生了什么。据我了解,一旦方法遇到 await 关键字,它就会有效返回,并在 Task 完成后继续执行。但是,这不是我观察到的行为。我有两个简单的方法:

public static async Task<bool> Level1()
{            
    var t = await Level2();      
    Console.WriteLine("L1 done.");  
    return t;                     
}

public static async Task<bool> Level2()
{
    int delay = 10;
    Thread.Sleep(100);
    var t = new TaskFactory();

    t.StartNew(() => { Thread.Sleep(delay); });
    Console.WriteLine("L2 done.");
    return true;
}

主要是,我调用

static void Main(string[] args)
{
    Level1();
    Console.WriteLine("Main done.");
}

现在,我希望 Main() 在调用 Level1() 之后继续执行,因为它没有被等待,并且因为 Level1() 包含一个 await 关键字。然而,结果输出是

L2 done.
L1 done.
Main done.

表示我的异步方法正在同步运行。修改 Level2() 使用 await 关键字解决问题,并且 Level1() 调用不再阻塞。为什么我需要在嵌套方法 Level2() 方法中使用“await”来防止 Level1() 阻塞 Main?

最佳答案

用 async 关键字标记方法不会使其成为异步的。它只允许使用 await(并用任务包装结果或异常)。

如果您有一个不等待其中任何异步操作的“异步”方法,则该方法是完全同步的,并将在调用线程上运行。

您可能遗漏的是,使用 await 并不一定会使方法异步运行,对未完成的任务使用 await 则可以。当任务已经完成时,没有理由暂停该方法。您可以直接从任务中获取结果并保持同步运行。

在您的情况下,Level2 同步运行。当 Level1 准备好等待其任务时,它已经完成,因此 Level2 保持同步运行。请记住,您等待的是一项任务,而不是一种方法,因此您的代码实际上是这样运行的:

public static async Task<bool> Level1()
{            
    var $task = Level2(); // Runs synchronously
    var t = await $task; // Awaiting a completed task      
    Console.WriteLine("L1 done.");  
    return t;                     
}

关于c# - 没有等待的嵌套异步方法 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33048523/

相关文章:

javascript - 如何让 .each() 等待每次迭代完成

c# - 以编程方式确定当前域 Controller

.net - 一个组件内的分层架构

javascript - 如何在nodeJS的forEach中正确使用async

c# - WPF 中基于动态百分比的宽度

c++ - C++中的浏览器帮助对象

javascript - javascript async/await 是如何工作的?

没有 IIS 的 c# rest webservice

c# - WPF 边框形状

c# - AutoComplete 是否适用于 WPF?