加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 18:20:40 所属栏目:百科 来源:网络整理
导读:这更多地出于好奇而不是任何现实世界的问题. 请考虑以下代码: void Main(){ FAsync().Wait();}async Task FAsync(){ await Task.Yield(); await FAsync();} 在同步世界中,这最终会导致堆栈溢出. 在异步世界中,这只会消耗大量内存(我认为这与我可能松散地称
这更多地出于好奇而不是任何现实世界的问题.

请考虑以下代码:

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允许我们在堆栈上保留一些信息.理解这种区别不是有必要了解如何以逻辑方式表示延续.)

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读