有没有办法让.Net JIT或C#编译器优化掉空的for循环?

11

关于此问题(Does .NET JIT optimize empty loops away?)的跟进:

以下程序运行了一个空循环十亿次并打印出运行时间。在我的机器上需要 700 毫秒,我想知道是否有办法让JIT编译器优化掉这个空循环。

using System;

namespace ConsoleApplication1 {
    class Program {
        static void Main() {
            var start = DateTime.Now;
            for (var i = 0; i < 1000000000; i++) {}
            Console.WriteLine((DateTime.Now - start).TotalMilliseconds);
        }
    }
}
据我所知,答案是否定的,但我不知道是否有隐藏的编译器选项我没有尝试过。我已经确保在发布模式下编译并且没有附加调试器,但是仍然需要700毫秒来运行这个空循环。我也尝试过使用NGEN得到了相同的结果(尽管我理解它应该产生与JIT相同的编译代码,对吗?)。但是我以前从未使用过NGEN,可能用错了方法。
看起来这似乎是JIT可以轻松找到并优化掉的东西,但由于我对jitters的工作原理知之甚少,我想知道为什么会忽略这种优化。此外,VC++编译器确实似乎做出了这种优化,那么为什么会有差异呢?有什么想法吗?

6
这对你来说为什么是问题?如果你有一个空的循环,就把它删掉就好了。 - Jon Skeet
这个跟你所提到的问题有什么不同? - Reed Copsey
5
不是空循环,它会将i增加十亿次。 - Bryan Walker
2
@Dax:那篇文章很糟糕。代码片段并不做相同的事情(提示:浮点数的运算顺序很重要)。你不能说苹果比橙子更快。 - R. Martinho Fernandes
3
这种优化的一个不寻常的用例是仅包含调试代码且在发布版本中为空的循环。尽管如此,让调试代码执行非常多次是很奇怪的,因此任何性能影响都会非常小。您也可以手动创建此优化,方法是将循环放入一个方法中,并注释该方法,以便仅在调试版本中调用它。 - Dan Bryant
显示剩余7条评论
1个回答

8
不,我所知道的.NET jitters都不会消除空的for循环。确切的原因对我来说并不清楚,Jitter优化器当然知道如何进行这样的优化,并且容易消除死代码。请参考此答案了解详情。我相信这是有意为之的,保留循环以便于其可能预期的副作用,消耗时间。当然,只有非常短的循环才实现自旋等待才有意义。

3
这种逻辑有点奇怪。优化代码的整个目的就是让它消耗更少的时间。如果你决定保持花费的时间不变,那么这会削弱优化的整个概念。 - jalf
4
自旋等待是一种优化技术。 - Hans Passant
看到空循环让我想起了编写不良的老式DOS程序,这些程序使用空循环来引入延迟或依赖于CPU定时来保持程序速度。运行非常老的游戏的DOS模拟器有时必须故意减缓CPU执行,以避免游戏以荒谬的帧速率更新。 - Dan Bryant
3
我听过最好的表达方式是这样的:“如果CPU时间的使用被包含在可观察行为中,那么所有的优化都是禁止的”。 - Ben Voigt
@DaxFohl,在自旋等待中,他们通常不使用空循环:他们会检查某些“volatile”变量的值,或者处理器周期计数,或高分辨率时钟。 - Serge Rogatch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接