【发布时间】:2012-02-14 06:01:03
【问题描述】:
我写了一些代码来测试 try-catch 的影响,但看到了一些令人惊讶的结果。
static void Main(string[] args)
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
long start = 0, stop = 0, elapsed = 0;
double avg = 0.0;
long temp = Fibo(1);
for (int i = 1; i < 100000000; i++)
{
start = Stopwatch.GetTimestamp();
temp = Fibo(100);
stop = Stopwatch.GetTimestamp();
elapsed = stop - start;
avg = avg + ((double)elapsed - avg) / i;
}
Console.WriteLine("Elapsed: " + avg);
Console.ReadKey();
}
static long Fibo(int n)
{
long n1 = 0, n2 = 1, fibo = 0;
n++;
for (int i = 1; i < n; i++)
{
n1 = n2;
n2 = fibo;
fibo = n1 + n2;
}
return fibo;
}
在我的计算机上,这始终会打印出大约 0.96 的值..
当我用这样的 try-catch 块将 for 循环包裹在 Fibo() 中时:
static long Fibo(int n)
{
long n1 = 0, n2 = 1, fibo = 0;
n++;
try
{
for (int i = 1; i < n; i++)
{
n1 = n2;
n2 = fibo;
fibo = n1 + n2;
}
}
catch {}
return fibo;
}
现在它始终打印出 0.69... -- 它实际上运行得更快!但为什么呢?
注意:我使用 Release 配置编译了这个并直接运行了 EXE 文件(在 Visual Studio 之外)。
编辑:Jon Skeet's excellent analysis 表明 try-catch 以某种方式导致 x86 CLR 在这种特定情况下以更有利的方式使用 CPU 寄存器(我认为我们还没有理解为什么)。我证实了 Jon 的发现,即 x64 CLR 没有这种差异,而且它比 x86 CLR 更快。我还在 Fibo 方法中使用 int 类型而不是 long 类型进行了测试,然后 x86 CLR 与 x64 CLR 一样快。
更新: Roslyn 似乎已修复此问题。相同的机器,相同的 CLR 版本 - 使用 VS 2013 编译时问题仍然存在,但使用 VS 2015 编译时问题消失。
【问题讨论】:
-
@Lloyd 他试图回答他的问题“它实际上运行得更快!但是为什么?”
-
所以,现在“吞咽异常”从一种不好的做法变成了一种很好的性能优化:P
-
这是在未经检查或检查的算术上下文中吗?
-
@taras.roshko:虽然我不想对 Eric 造成伤害,但这并不是一个真正的 C# 问题——它是一个 JIT 编译器问题。最终的困难是弄清楚为什么 x86 JIT 在没有 try/catch 的情况下使用的寄存器数量不如 使用 try/catch 块。
-
很好,所以如果我们嵌套这些 try catch,我们可以走得更快,对吧?
标签: c# .net clr try-catch performance-testing