虽然这只是一种微小的优化,不会成为性能瓶颈。但有趣的是,实际上这两者是不同的,有趣的是,当你提取方法时,使用VS2010运行两个循环时,我得到以下结果:
private static String forLoop(ref Int64 i)
{
String x;
for (; FIVE_BN > i; i++)
x = null;
return x;
}
private static void whileloop(ref String x, ref Int64 i)
{
while (FIVE_BN > i++)
x = null;
}
这十分有趣……它表明这两个函数确实是不同的。
现在,当我们用 ;
替换循环中的逻辑时,我们得到了以下抽取方法:
private static Int64 forLoopShort(Int64 i)
{
for (; FIVE_BN > i; i++)
; //Replace with only ; in both loops and the for loop is faster
return i;
}
private static Int64 whileLoopShort(Int64 i)
{
while (FIVE_BN > i++)
; //Replace with only ; in both loops and the for loop is faster
return i;
}
这就解释了为什么使用这种配置时循环基本上运行相同。
要想知道它们在内联时(而不是提取到方法中时)有什么不同,我们需要查看优化后的CLR代码长什么样子(尽管优化器实际上可能会消除两个函数之间的任何显著差异)。这是留给以后编辑的事情。
编辑:
CIL显示了区别:
For循环具有.maxstack 2
,而while循环具有.maxstack 4
,否则由于while
的递增发生在循环开始时,而for
操作发生在循环结束时,因此操作顺序有一点点不同(将循环内容更改为Console.WriteLine(i)
,可以看到While循环将从1打印,但For循环将从0打印(尽管两个循环都执行相同数量的循环迭代)。
当循环内容只是;
时,两个循环在CIL中都短了2行,以下行被删除(对于两个循环都是如此):
IL_0006: ldnull
IL_0007: stloc.0
然而当我们使用发布版本进行构建时,代码会非常不同:
x = null;
和;
在任何一个循环中的区别都是无关紧要的,因为优化器已经注意到该值永远不会变成非null。
优化后的for
循环和while
循环之间的区别如下:
CIL for
循环:
IL_0000: ldc.i4.0
IL_0001: conv.i8
IL_0002: stloc.0
IL_0003: br.s IL_000a
IL_0005: ldloc.0
IL_0006: ldc.i4.1
IL_0007: conv.i8
IL_0008: add
IL_0009: stloc.0
IL_000a: ldc.i8 0x12a05f200
IL_0013: ldloc.0
IL_0014: bgt.s IL_0005
IL_0016: ret
关于CIL中的while
循环:
IL_0000: ldc.i4.0
IL_0001: conv.i8
IL_0002: stloc.0
IL_0003: ldc.i8 0x12a05f200
IL_000c: ldloc.0
IL_000d: dup
IL_000e: ldc.i4.1
IL_000f: conv.i8
IL_0010: add
IL_0011: stloc.0
IL_0012: bgt.s IL_0003
IL_0014: ret
我们可以看到,优化后的while循环比for循环快2个操作,但是它使用更多的堆栈空间。
这两者之间的区别似乎完全与i++出现的位置有关。
确实,通过创建一个新的方法来确认这一点:
private static void forLoopVeryShort()
{
string x;
Int64 i = 0;
for (; FIVE_BN > i++;)
;
}
无论是在发布版还是调试版中编译生成的这个for
方法的CIL代码与while
循环的代码完全相同。
这就是它们之间的区别。当它们执行完全相同的行为时,for
循环和while
循环的表现也完全相同。你提到的差异完全是由于在调试模式下运行代码,而JIT并不总是像发布版代码优化器一样高效。
我喜欢这个问题,我从中学到了东西,希望其他人也能受益。+1
DateTime
- 应使用专为此类用途设计的Stopwatch
类。 - OdedStopwatch
进行性能计时,并进行多次运行以过滤掉冷启动被JIT编译的开销(基本上忽略第一次运行)。 - Adam Houldsworth