2009-11-10 26 views
37

除了確保它們不能被更改(以適應編譯器錯誤)外,JIT是否對const本地進行了任何優化?使用const局部變量有沒有運行時好處?

EG。

public static int Main(string[] args) 
{ 
    const int timesToLoop = 50; 

    for (int i=0; i<timesToLoop; i++) 
    { 
     // ... 
    } 
} 
+3

運行時間的好處?我的直覺是它應該更有效率,儘管可能微不足道。我也很好奇答案。 – 2009-11-10 13:31:12

+0

因爲這可能會導致編譯時優化,所以我懷疑它的優化方式與全局常量相同。 – Lazarus 2009-11-10 13:42:12

+0

我意識到任何優化都是微不足道的,它更像是一個好奇的問題:) – 2009-11-10 14:15:05

回答

70

所生成的IL是不同的(使用釋放模式):

using constant local     using normal local 
--------------------------------------------------------------------- 
.entrypoint       .entrypoint 
.maxstack 2       .maxstack 2 
.locals init (      .locals init (
    [0] int32 i)       [0] int32 timesToLoop, 
L_0000: ldc.i4.0       [1] int32 i) 
L_0001: stloc.0      L_0000: ldc.i4.s 50 
L_0002: br.s L_0008     L_0002: stloc.0 
L_0004: ldloc.0      L_0003: ldc.i4.0 
L_0005: ldc.i4.1      L_0004: stloc.1 
L_0006: add       L_0005: br.s L_000b 
L_0007: stloc.0      L_0007: ldloc.1 
L_0008: ldloc.0      L_0008: ldc.i4.1 
L_0009: ldc.i4.s 50     L_0009: add 
L_000b: blt.s L_0004     L_000a: stloc.1 
L_000d: ret       L_000b: ldloc.1 
             L_000c: ldloc.0 
             L_000d: blt.s L_0007 
             L_000f: ret 

正如你可以看到編譯器通過其導致更小的堆疊中的常數的值替換所有變量用法。

+20

+1抽空查看IL! – MagicAndi 2009-11-10 13:39:42

+0

除了一個不顯眼的小堆棧外,其功能是一樣的。雖然有趣。 – kenny 2009-11-10 13:48:54

+2

很好的答案,很好地格式化! – 2009-11-10 14:14:25

3

這不是一個答案附近的任何地方,只是認爲這將是很好的分享這不過文章沒有明確提到運行好處:
Coding Standard Rule #2: Use const Wherever Possible

摘錄:
推理:使用的上攻儘可能的const是編譯器強制的保護,防止意外的寫入到應該是隻讀的數據。

0

一個區別是,如果您有一個程序集在另一個程序集中引用了const字段,並且以後更改了該值,則引用程序集仍會在重建之前使用舊值。

+3

這個問題涉及到const locals,而不是const字段/成員。 – 2009-11-10 14:12:52

5

你的代碼(使用常量)實際上會被編譯爲:

public static int Main(string[] args){  
    for (int i=0; i < 50; i++) 
    { 

    } 
} 

而變量將編譯爲一個變量:

public static int Main(string[] args){ 
    int timesToLoop = 50;  
    for (int i=0; i < timesToLoop; i++) 
    { 

    } 
} 
10

我給的代碼快速的性能測試,採用Snippet Compiler 。我使用的代碼如下:

public static void Main() 
    { 
     DateTime datStart = DateTime.UtcNow; 
     const int timesToLoop = 1000000; 

     for (int i=0; i < timesToLoop; i++) 
     { 
      WL("Line Number " + i.ToString()); 
     } 

     DateTime datEnd = DateTime.UtcNow; 
     TimeSpan tsTimeTaken = datEnd - datStart; 
     WL("Time Taken: " + tsTimeTaken.TotalSeconds); 
     RL(); 
    } 

注意,WL和RL僅僅是輔助方法來讀取和寫入到控制檯。

要測試非常量版本,我只是刪除const關鍵字。結果令人驚訝:

     Time Taken (average of 3 runs) 

Using const keyword   26.340s 
Without const keyword  28.276s 

我知道,這是非常rough'n'ready測試,而是使用了const關鍵字似乎算作一個有效micro-optimization

+14

說到微觀優化,您應該使用'DateTime.UtcNow'而不是'DateTime.Now',因爲前者不需要從操作系統查找本地時區。 – 2009-11-10 15:11:12

+0

理查德,謝謝,一個新的提示! – MagicAndi 2009-11-10 16:09:44

相關問題