看看这段代码:
public async Task<T> ConsumeAsync()
{
await a();
await b();
await c();
await d();
//..
}
让我们说a,b,c,d
也有嵌套异步等待(依此类推)
Async / await POV - 对于每个await
,都有一台状态机。
问题(理论):
由于每个状态机都保存在内存中,这是否会导致大量内存消耗? 这可能是一个模糊的问题,但如果有很多州,似乎不可避免地想到保留国家机器的大小。
异步/等待POV - 对于每个等待,都有一个状态机被保留。
不对。编译器为每个async
方法生成状态机。方法中的本地提升到状态机上的字段中。该方法的主体(基本上)被分解为switch
语句,每个case
对应于await
语句之间的方法的一部分。 int
用于跟踪方法的哪个位已被执行(即接下来应该执行哪个case
)。
您的方法a()
,b()
等可能有自己的状态机,或者它们可能没有(取决于它们是否标记为async
)。即使他们这样做,在您的示例中,一次只会实例化其中一个状态机。
SharpLab是探索这些东西的绝佳资源。 Example。
由于每个状态机都保存在内存中,这是否会导致大量内存消耗?
非常不可能。每个状态机在外面占用几十个字节。
所以只有当你拥有很多这样的东西时才会有意义。嵌套并不会真正导致这种情况,但执行Task[]
的成员可能会。
但这与任何其他资源类型并不是新的或不同的。
需要额外付费,但相对较小。
与常规功能相比的额外成本:
此外,函数的局部变量将转换为状态机的字段。这会将一些内存从堆栈移到堆中。
我建议反编译一些简单的异步函数,以查看生成的状态机并具有直观的期望。
还有一些在线工具可以做到这一点(如sharplab.io)请参阅results of decompilation of a trivial async function