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