c# – 异步递归.我的记忆在哪里?

前端之家收集整理的这篇文章主要介绍了c# – 异步递归.我的记忆在哪里?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这更多地出于好奇而不是任何现实世界的问题.

请考虑以下代码

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

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

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

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

这些数据到底是什么,以及如何保存?

解决方法

好问题.

堆栈是延续的具体化.简单地说,继续是关于该计划下一步将要做什么的信息.在传统的非异步环境中,这表示为堆栈上的返回地址;当方法返回时,它查看堆栈并分支到返回地址.堆栈上还有关于局部变量的值在延续点处的位置的信息.

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

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

这里有一篇关于这一切如何运作的好的介绍性文章

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

自从Mads撰写该文章以来,一些细节已经改变,但这些想法是合理的. (i3arnon的答案说明了这种演变的方式;在Mads的文章中,所有内容都在堆上,但事实证明在某些情况下会产生过多的垃圾.更复杂的codegen允许我们在堆栈上保留一些信息.理解这种区别不是有必要了解如何以逻辑方式表示延续.)

这是一个有趣和有启发性的练习,可以获取您的程序并实际绘制出创建的所有委托和任务,以及它们之间的引用.试一试!

原文链接:https://www.f2er.com/csharp/98241.html

猜你在找的C#相关文章