gpt4 book ai didi

c# - 异步递归。我的内存到底去哪儿了?

转载 作者:IT王子 更新时间:2023-10-28 23:37:00 25 4
gpt4 key购买 nike

这个问题更多是出于好奇,而不是针对任何现实世界的问题。

考虑以下代码:

void Main()
{
FAsync().Wait();
}

async Task FAsync()
{
await Task.Yield();
await FAsync();
}

在同步世界中,这最终会导致堆栈溢出。

在异步世界中,这只会消耗大量内存(我假设这与我可能松散地称为“异步堆栈”的东西有关?)

这些数据究竟是什么,它是如何保存的?

最佳答案

好问题。

堆栈是延续的具体化。简单地说,继续是关于程序接下来要做什么的信息。在传统的非异步环境中,这表示为堆栈上的返回地址;当方法返回时,它查看堆栈并分支到返回地址。堆栈上还包含有关局部变量在延续开始时的值的信息。

在异步情况下,所有信息都存储在堆上。任务包含在任务完成时调用的委托(delegate)。委托(delegate)绑定(bind)到“闭包”类的实例,该类包含任何局部变量或其他状态的字段。当然,任务本身就是堆对象。

您可能想知道:如果延续是在任务完成时调用的委托(delegate),那么完成任务的代码如何不在调用堆栈上完成在哪里执行?任务可以选择通过发布 Windows 消息来调用延续委托(delegate),并且当消息循环处理消息时,它会执行调用。因此,调用位于堆栈的“顶部”,消息循环通常位于该位置。 (用于延续的调用策略的精确细节取决于创建任务的上下文;有关详细信息,请参阅任务并行库的更高级指南。)

可以在此处找到一篇很好的介绍性文章,了解这一切是如何工作的:

https://msdn.microsoft.com/en-us/magazine/hh456403.aspx

自 Mads 撰写那篇文章以来,一些细节发生了变化,但这些想法是合理的。 (i3arnon 的回答说明了这是如何演变的;在 Mads 的文章中,一切都在堆上进行,但事实证明这在某些情况下会产生过多的垃圾。更复杂的代码生成器允许我们将一些信息保留在堆栈上。理解这种区别并不是有必要看看延续是如何在逻辑上表示的。)

这是一个有趣且有启发性的练习,让您的程序实际绘制出所有创建的委托(delegate)和任务,以及它们之间的引用是什么。试一试!

关于c# - 异步递归。我的内存到底去哪儿了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35464468/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com