我了解 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
时会发生什么调用 A
? A
立即调用 B
.但是B
等待延迟。这是真的async
所以整个调用栈展开。但是一毫秒后,B
的状态机将结束,并为 A
调用继续状态. A
的状态机将依次结束并调用 Main
的继续状态.最后,Main
的状态机, 拥有 A
的返回值, 写出 1
到控制台。
关于c# - 说丢弃任务的非异步方法位于异步等待链的 "top"是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47744949/