2010-10-12 121 views
6

在循環內或循環外聲明變量是否更快?例如:更快地聲明循環內部或循環外部的變量?

' Declaration inside of the loop 
For each item in items 
    Dim newVariable as String = GetAString() 
Next 

' Declaration outside of the loop 
Dim newVariable as String = String.Empty 
For each item in items 
    newVariable = GetAString() 
Next 

哪一個更快?爲什麼?我認爲後者更快,因爲它只是重複使用相同的「指針」在幕後引用新值,而不是每次迭代都創建新指針,是正確的?有人可以詳細說明嗎?

由於

更新:產生中間語言時

編譯器是足夠的智能來優化代碼。它將變量聲明移動到方法的頂部。下面是IL內declartions編譯後:

.locals init ([0] string newVariable2, 
      [1] int32 i, 
      [2] string newVariable, 
      [3] int32 V_3, 
      [4] int32 VB$CG$t_i4$S0) 

這裏就是整個IL對於那些有興趣:

.method private instance void Form1_Load(object sender, 
              class [mscorlib]System.EventArgs e) cil managed 
{ 
    // Code size  55 (0x37) 
    .maxstack 2 
    .locals init ([0] string newVariable2, 
      [1] int32 i, 
      [2] string newVariable, 
      [3] int32 V_3, 
      [4] int32 VB$CG$t_i4$S0) 
    IL_0000: nop 
    IL_0001: ldc.i4.0 
    IL_0002: stloc.1 
    IL_0003: ldarg.0 
    IL_0004: callvirt instance string WindowsApplication1.TestVariableDeclaration::getstring() 
    IL_0009: stloc.2 
    IL_000a: nop 
    IL_000b: ldloc.1 
    IL_000c: ldc.i4.1 
    IL_000d: add.ovf 
    IL_000e: stloc.1 
    IL_000f: ldloc.1 
    IL_0010: ldc.i4  0x989680 
    IL_0015: stloc.s VB$CG$t_i4$S0 
    IL_0017: ldloc.s VB$CG$t_i4$S0 
    IL_0019: ble.s  IL_0003 
    IL_001b: ldc.i4.0 
    IL_001c: stloc.3 
    IL_001d: ldarg.0 
    IL_001e: callvirt instance string WindowsApplication1.TestVariableDeclaration::getstring() 
    IL_0023: stloc.0 
    IL_0024: nop 
    IL_0025: ldloc.3 
    IL_0026: ldc.i4.1 
    IL_0027: add.ovf 
    IL_0028: stloc.3 
    IL_0029: ldloc.3 
    IL_002a: ldc.i4  0x989680 
    IL_002f: stloc.s VB$CG$t_i4$S0 
    IL_0031: ldloc.s VB$CG$t_i4$S0 
    IL_0033: ble.s  IL_001d 
    IL_0035: nop 
    IL_0036: ret 
} // end of method TestVariableDeclaration::Form1_Load 
+1

也許編譯器會優化它?最佳建議:啓動IDE,實例化秒錶,並運行每個版本的幾千次迭代,看看是否有真正的差異。 – 2010-10-12 18:20:18

+0

好主意! Brb與結果.. – Moderator71 2010-10-12 18:22:39

+4

你是想解決一個實際的性能問題,或者你只是無聊和玩弄微型優化,永遠不會在真實世界的應用程序有意義的區別? – JohnFx 2010-10-12 18:25:52

回答

11

我同意凱文的回答,定義他們有意義的變量。擔心優化是否以及何時出現,並且您知道變量聲明是問題。然而,考慮代碼

void Test1() 
{ 
    foreach (int i in Enumerable.Range(0,10)) 
    { 
     string s = GetString(); 
     Console.WriteLine(s); 
    } 
} 

void Test2() 
{ 
    string s; 
    foreach (int i in Enumerable.Range(0,10)) 
    { 
     s = GetString(); 
     Console.WriteLine(s); 
    } 
} 

以下兩個部分,併產生了IL:

Test1: 
IL_0000: ldc.i4.0  
IL_0001: ldc.i4.s 0A 
IL_0003: call  System.Linq.Enumerable.Range 
IL_0008: callvirt System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator 
IL_000D: stloc.1  
IL_000E: br.s  IL_0024 
IL_0010: ldloc.1  
IL_0011: callvirt System.Collections.Generic.IEnumerator<System.Int32>.get_Current 
IL_0016: pop   
IL_0017: ldarg.0  
IL_0018: call  UserQuery.GetString 
IL_001D: stloc.0  
IL_001E: ldloc.0  
IL_001F: call  System.Console.WriteLine 
IL_0024: ldloc.1  
IL_0025: callvirt System.Collections.IEnumerator.MoveNext 
IL_002A: brtrue.s IL_0010 
IL_002C: leave.s  IL_0038 
IL_002E: ldloc.1  
IL_002F: brfalse.s IL_0037 
IL_0031: ldloc.1  
IL_0032: callvirt System.IDisposable.Dispose 
IL_0037: endfinally 
IL_0038: ret   

Test2: 
IL_0000: ldc.i4.0  
IL_0001: ldc.i4.s 0A 
IL_0003: call  System.Linq.Enumerable.Range 
IL_0008: callvirt System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator 
IL_000D: stloc.1  
IL_000E: br.s  IL_0024 
IL_0010: ldloc.1  
IL_0011: callvirt System.Collections.Generic.IEnumerator<System.Int32>.get_Current 
IL_0016: pop   
IL_0017: ldarg.0  
IL_0018: call  UserQuery.GetString 
IL_001D: stloc.0  
IL_001E: ldloc.0  
IL_001F: call  System.Console.WriteLine 
IL_0024: ldloc.1  
IL_0025: callvirt System.Collections.IEnumerator.MoveNext 
IL_002A: brtrue.s IL_0010 
IL_002C: leave.s  IL_0038 
IL_002E: ldloc.1  
IL_002F: brfalse.s IL_0037 
IL_0031: ldloc.1  
IL_0032: callvirt System.IDisposable.Dispose 
IL_0037: endfinally 
IL_0038: ret 

見有什麼區別?那些編譯器傢伙,他們很聰明。

+0

使用秒錶並不是很有用。我得到了不同的結果,但看着IL是人爲的。本質上,編譯器將聲明移到IL中方法的頂部。我會編輯我的帖子,以澄清IL。 – Moderator71 2010-10-12 19:08:22

2

我能想象得到優化器知道這些是相同的,因此,他們變成具有相同的性能。它可能不會。您可以檢查目標代碼或度量。

4

都沒有。你仍然在循環的每次迭代中創建一個新的字符串,所以它們將是相同的。即使有一個,你在大範圍的事情上所採取的是令人難以置信的微不足道的。

變量的作用域聲明是會改變的,如果你不需要它在循環之外,那麼你應該把它放在裏面。