我理解async
方法本身是如何工作的:编译器将其转换为创建状态机(在堆上)的代码,以便该方法生效"暂停"它到达await
并返回Task
并且调用堆栈展开。在"底部"这个链的一种方法只是简单地返回一个任务,通常是在开始自然异步" I / O等过程。
那么," top&#34 ;?我想最顶层的方法只是丢弃任务,所以它可以继续前进。那是对的吗?
如果我们的执行上下文是Windows窗体应用程序和" top"也许最简单的方式可以解释这个问题。是消息泵。
答案 0 :(得分:3)
通常没有任何东西在顶部。您描述的状态机的重点是,当异步操作完成时,它会在状态机的MoveNext
方法上执行回调(该名称是yield
运算符基本上是async
语义的原始前兆。这个过程并不是真正基于callstack的,它更类似于对你的某些方法进行回调的事件(在这种情况下,是编译器生成的MoveNext
方法)。
所以为了回答你的问题,异步方法"完成"。一直到链,每个异步方法"完成"。但是当实际的异步进程进行回调时,事情就会重新开始。链上的每个异步方法都会对后一帧的MoveNext
方法进行后续回调,允许在callstack中的前一帧恢复"恢复"。
请考虑以下代码:
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
所以整个callstack都会展开。但是在一毫秒之后,B
的状态机将结束,并调用A
的继续状态。 A
的状态机将依次包装并调用Main
的继续状态。最后,Main
的状态机拥有A
的返回值,将1
写入控制台。