更快地在循环内或循环外声明变量?

时间:2010-10-12 18:16:52

标签: .net variables loops optimization declaration

在循环内或循环外声明变量是否更快?例如:

' 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中的声明:

 .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

3 个答案:

答案 0 :(得分:12)

我同意Kevin的回答,定义具有意义的变量。如果他们出现自己并且您知道变量声明是问题,那么担心优化。但是,请考虑以下两段代码

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   

看到有什么区别?那些编译人员,他们很聪明。

答案 1 :(得分:4)

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

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

答案 2 :(得分:2)

我可以想象优化器知道它们是相同的,因此它们具有相同的性能。它可能不会。您可以检查目标代码或测量。