雖然這完全是一個微不足道的優化問題。有趣的是,這兩個實際上是不同的,有趣的是,當你提取方法均環與VS2010我得到如下:
private static String forLoop(ref Int64 i)
{
String x;
for (; FIVE_BN > i; i++)
x = null; //Replace with only ; in both loops and the for loop is faster
return x;
}
private static void whileloop(ref String x, ref Int64 i)
{
while (FIVE_BN > i++)
x = null; //Replace with only ; in both loops and the for loop is faster
}
這是很有趣......這表明,這兩種功能是確有不同。
現在當我們;
替換循環的邏輯,我們得到以下的提取方法代替:
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打印(兩者都會盡管循環次數相同)
當環路內容只是一個;
兩個環路是2線短於CIL除去了以下行(兩個迴路):
IL_0006: ldnull
IL_0007: stloc.0
然而,當我們建立在釋放代碼非常不同:
對於任一循環,x = 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++;)
; //Replace with only ; in both loops and the for loop is faster
}
爲內置當此for
方法(在任一釋放或調試)CIL代碼是相同的,所述while
循環。
有謊言你的區別。當循環執行完全相同的行爲時,循環執行與while循環完全相同。您注意到的差異完全是由於在調試中運行代碼而不是發佈,與JIT並不總是像發佈代碼優化器一樣高效。
我很喜歡這個問題,我從中學到了一些東西;我希望別人也這樣做。 +1
不要使用'DateTime'作爲基準 - 使用專門用於這種用途的'Stopwatch'類。 – Oded 2012-01-09 10:18:45
也許某些東西已經被你的編譯器優化了。 – 2012-01-09 10:18:46
只需幾個指針,嘗試使用'Stopwatch'進行性能計時,並執行多次運行以過濾掉正在進行JIT運行的冷啓動(基本忽略第一次運行)。 – 2012-01-09 10:19:00