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

时间:2017-12-11 00:25:24

标签: c# .net asynchronous async-await task

我理解async方法本身是如何工作的:编译器将其转换为创建状态机(在堆上)的代码,以便该方法生效"暂停"它到达await并返回Task并且调用堆栈展开。在"底部"这个链的一种方法只是简单地返回一个任务,通常是在开始自然异步" I / O等过程。

那么," top&#34 ;?我想最顶层的方法只是丢弃任务,所以它可以继续前进。那是对的吗?

如果我们的执行上下文是Windows窗体应用程序和" top"也许最简单的方式可以解释这个问题。是消息泵。

1 个答案:

答案 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写入控制台。