【问题标题】:Is there a way to get the .Net JIT or C# compiler to optimize away empty for-loops?有没有办法让 .Net JIT 或 C# 编译器优化空的 for 循环?
【发布时间】:2011-11-09 10:43:11
【问题描述】:

Does .NET JIT optimize empty loops away?的后续行动:

下面的程序只是运行一个空循环十亿次并打印出运行时间。我的机器上需要 700 毫秒,我很好奇是否有办法让抖动优化掉空循环。

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 来说很容易找到并优化掉,但对抖动的一般工作原理知之甚少,我很好奇这种优化是否有特定原因被排除在外。此外,VC++ 编译器似乎确实做了这种优化,所以我想知道为什么会出现这种差异。有什么想法吗?

【问题讨论】:

  • 为什么在现实中这对您来说是个问题?如果你有一个空循环,就把它去掉。
  • 这与您引用的问题有何不同?
  • 这不是一个空循环。它增加了 i 十亿倍。
  • @Dax:那篇文章很糟糕。代码 sn-ps 不做同样的事情(提示:浮点数的操作顺序事项)。你不能说苹果是否比橘子快。
  • 这个优化的一个公认不寻常的用例是只包含调试代码的循环,因此在发布版本中是空的。也就是说,让 Debug 代码执行很多次是很奇怪的,因此任何性能影响都会非常小。您还可以通过将循环放入方法并注释该方法来手动创建此优化,以便仅在 Debug 构建中调用它。

标签: c# .net clr jit compiler-optimization


【解决方案1】:

不,我所知道的任何 .NET 抖动都不会消除空的 for 循环。确切的原因对我来说不是那么清楚,抖动优化器当然知道如何进行这样的优化并且很容易消除死代码。详情请查看this answer。我相信这是故意的,将循环留在原地,因为它可能会产生预期的副作用,耗费时间。这当然只对非常短的循环来实现 spinwait 有意义。

【讨论】:

  • 这是一种奇怪的逻辑。优化代码的全部目的是使其消耗更少的时间。如果您决定保留所花费的时间,这会破坏优化的整个想法。
  • 旋转等待是一种优化。
  • 看到空循环让我想起了写得很糟糕的老式 DOS 程序,这些程序使用空循环来引入延迟或依靠 CPU 计时来提高程序速度。运行非常老的游戏的 DOS 模拟器有时必须故意限制 CPU 执行,以使游戏不会以荒谬的帧速率更新。
  • @jalf:我听到的最好的表述是“如果 CPU 时间的使用包含在 可观察行为 中,则禁止所有优化”。
  • @DaxFohl,在自旋等待中,它们通常不使用空循环:它们检查某些 volatile 变量的值,或处理器周期计数或高分辨率时钟。
猜你喜欢
  • 1970-01-01
  • 2016-05-25
  • 1970-01-01
  • 2010-09-21
  • 2020-10-19
  • 1970-01-01
  • 2019-03-06
  • 2012-12-11
  • 1970-01-01
相关资源
最近更新 更多