gpt4 book ai didi

c# - 为什么编译器不能通过内联来优化闭包变量?

转载 作者:太空狗 更新时间:2023-10-29 18:21:31 25 4
gpt4 key购买 nike

我有一个像这样的 Main 方法:

static void Main(string[] args)
{
var b = new byte[1024 * 1024];

Func<double> f = () =>
{
new Random().NextBytes(b);
return b.Cast<int>().Average();
};

var avg = f();
Console.WriteLine(avg);
}

因为我在这里访问局部变量 b ,所以编译器创建了一个类来捕获该变量,并且 b 成为该类的字段。然后 b 的生命周期与编译器生成的类的生命周期一样长,它会导致内存泄漏。即使 b 超出范围(在这种情况下可能不会,但可以想象这是在另一个方法内部而不是 Main),字节数组也不会被释放。

我想知道的是,因为在声明 Func 之后我没有在任何地方访问或修改 b,为什么编译器不能内联那个局部变量而不用理会创建一个类?像这样:

Func<double> f = () =>
{
var b = new byte[1024 * 1024];
new Random().NextBytes(b);
return b.Cast<int>().Average();
};

我在 Debug 和 Release 模式下编译了这段代码,DisplayClass 是在两种模式下生成的:

enter image description here

这只是没有作为优化实现,还是我遗漏了什么?

最佳答案

Is this just not implemented as an optimization or is there anything I am missing?

对于您给出的具体示例,您可能不想进行该代码转换,因为它会改变程序的语义。如果 new 抛出异常,在原始程序中它应该在委托(delegate)执行之前抛出异常,而在您的转换中,副作用会被延迟。这是否是一个应该保留的重要属性(property)是值得商榷的。 (这样做也会给调试器带来问题;调试器已经必须假装闭包类的元素是包含方法体的局部元素,而这种优化可能会使它进一步复杂化。)

然而,更一般的一点是密切相关的。如果您知道封闭变量仅用于其值,则可以进行许多优化。

当我在编译器团队时——我于 2012 年离开——我和 Neal Gafter 考虑实现此类优化,以及一些更复杂的优化,旨在降低昂贵对象生命周期延长过长的可能性意外地。

旁白:最复杂的场景中最简单的是:我们将两个 lambda 转换为委托(delegate);一个存储在一个短暂的变量中,并在包含对昂贵对象的引用的局部变量上关闭;一个存储在一个长期存在的变量中,并在引用廉价对象的局部变量上关闭。昂贵的对象与长生命周期变量一样长,即使它没有被使用。更一般地,可以将多个闭包构造为基于封闭关系的分区;当时我们只根据嵌套来划分闭包;同一嵌套级别的闭包是一个闭包。给定的场景很少见,并且有明显的解决方法,但如果它根本没有发生就好了。

我们没有这样做是因为在我们实现 Roslyn 期间有更多重要的优化和功能,我们不想给已经很长的时间表增加风险。

我们可以自信地执行此类优化,因为在 C# 中,很容易知道本地何时被别名,因此您可以确定它是否在创建闭包后被写入。

我不知道这些优化是否同时实现了;可能不会。

我也不知道编译器是否对 C# 7 本地函数进行了此类优化,但我怀疑答案是"is"。看看如果您尝试使用本地函数会发生什么!

关于c# - 为什么编译器不能通过内联来优化闭包变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52087314/

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