我有以下C#代码尝试在发布模式下进行基准测试:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication54 { class Program { static void Main(string[] args) { int counter = 0; var sw = new Stopwatch(); unchecked { int sum = 0; while (true) { try { if (counter > 20) throw new Exception("exception"); } catch { } sw.Restart(); for (int i = 0; i < int.MaxValue; i++) { sum += i; } counter++; Console.WriteLine(sw.Elapsed); } } } } }
我在64位机器上安装了VS 2015.当我在32位下运行代码时,它每次迭代运行大约0.6秒,打印到控制台.当我在64位下运行时,每次迭代的持续时间只需跳到4秒!我在我的同事计算机上尝试了示例代码,该计算机只安装了VS 2013. 32位和64位版本都运行大约0.6秒.
除此之外,如果我们只删除try catch块,它也会在0.6秒内运行,VS 2015在64位.
当有一个try catch块时,这看起来像一个严重的RyuJIT回归.我对么 ?
解决方法
基准测试是一门艺术.对您的代码进行一些小修改:
Console.WriteLine("{0}",sw.Elapsed,sum);
你现在看到差异消失了.换句话说,x86版本现在和x64代码一样慢.你可以弄清楚RyuJIT没有做什么传统的抖动从这个微小的变化做了什么,它并没有消除不必要的
sum += i;
使用Debug>查看生成的机器代码时可以看到的内容Windows>拆卸.这在RyuJIT确实是一个怪癖.其死代码消除不如传统抖动那么彻底.否则不完全没有理由,微软重写了x64抖动,因为它无法轻易解决的错误.其中一个是优化器的一个相当讨厌的问题,它在优化方法上花费的时间没有上限.在具有非常大的物体的方法上导致相当差的行为,它可能在树林中出现几十毫秒并导致明显的执行暂停.
把它称为虫子,嗯,不是真的.写出合理的代码和抖动不会让你失望.优化确实始于通常的位置,在程序员的耳朵之间.