c# - 说丢弃任务的非异步方法位于异步等待链的 "top"是否正确?

标签 c# .net asynchronous async-await task

我了解 async 方法本身是如何工作的:编译器将其转换为创建状态机(在堆上)的代码,以便该方法在到达 await 并返回一个 Task 并且调用堆栈展开。这条链的“底部”是一个简单地返回任务的方法,通常是在启动“自然异步”进程(例如 I/O)之后。

那么,“顶”是什么?我想最顶层的方法只是丢弃任务,以便它可以继续。那是对的吗?

如果我们的执行上下文是一个 Windows 窗体应用程序,而“顶部”是消息泵,那么有人可以描述这一点的最简单方法。

最佳答案

通常顶部没有任何内容。您描述的状态机的全部要点是,当异步操作完成时,它会在状态机的 MoveNext 上执行回调方法(名称是 yield 运算符的遗留物,本质上是 async 语义的原始前身)。此过程并非真正基于调用堆栈,它更类似于对您的某些方法(在本例中为编译器生成的 MoveNext 方法)进行回调的事件。

因此,为了回答您的问题,异步方法“完成”了。一直沿着链向上,每个异步方法“完成”。但是当实际的异步进程进行回调时,事情会恢复。链上的每个异步方法都会对前一帧的 MoveNext 进行后续回调。方法,允许调用堆栈中的先前帧“恢复”。

考虑以下代码:

static async void Main()
{
    Console.WriteLine(await A());
}

static async Task<int> A()
{
    return await B();
}

static async Task<int> B() 
{
    await Task.Delay(1);
    return 1;
}

执行 Main 时会发生什么?如果这是一个普通的静态 Main没有 async 的方法入口点,这将是一个问题,因为您会立即退出该程序。这是当您使用 async 时产生这种想法的原因之一。你需要使用它 all the way up the callstack .使用 C# 7.1,您实际上可以提供 async入口点。

Main 时会发生什么调用 AA立即调用 B .但是B等待延迟。这是真的async所以整个调用栈展开。但是一毫秒后,B 的状态机将结束,并为 A 调用继续状态. A 的状态机将依次结束并调用 Main 的继续状态.最后,Main 的状态机, 拥有 A 的返回值, 写出 1到控制台。

关于c# - 说丢弃任务的非异步方法位于异步等待链的 "top"是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47744949/

相关文章:

c# - "deep freeze"是如何工作的?

c# - 如何将 Font 保留在继承的 TextBox 中?

c# - 更改集合中的结构

c# - 将 Logo 附加到 ASP.NET 生成的电子邮件时出错

c# - 使用简单注入(inject)器注册多个电子邮件输出服务

.net - 使用 CI CD Azure DevOps 部署之前使 APP 脱机

c# - 新手 caSTLe windsor 并尝试创建我的接口(interface)的实现

asynchronous - Dart 中的 await 关键字会自动处理数据依赖吗?

javascript - 在 Promises 中使用循环的正确方法

asynchronous - Flutter:Dialog 是否位于 Navigator(堆栈)之上?