2010-10-12 122 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

都没有。你仍然在循环的每次迭代中创建一个新的字符串,所以它们将是相同的。即使有一个,你在大范围的事情上所采取的是令人难以置信的微不足道的。

变量的作用域声明是会改变的,如果你不需要它在循环之外,那么你应该把它放在里面。