2010-10-12 16 views
6

¿Es más rápido para declarar variables dentro de un bucle o fuera de un bucle? Por ejemplo:¿Más rápido para declarar variables dentro de un bucle o fuera de un bucle?

' 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 

¿Cuál es más rápido? ¿Por qué? Asumo que este último es más rápido, ya que se acaba de volver a utilizar el mismo "puntero" para hacer referencia a un nuevo valor detrás de las escenas en lugar de crear un nuevo puntero de cada iteración, correcto? ¿Puede alguien elaborar?

Gracias

Actualizado:

El compilador es suficientemente inteligente para optimizar el código cuando se genera el lenguaje intermedio. Mueve las declaraciones de variables a la parte superior del método. A continuación, es el declartions dentro de la IL después de la compilación:

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

Aquí está toda la IL para los interesados:

.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

Tal vez el compilador optimizarlo? El mejor consejo: inicie su IDE, crea instancias de un cronómetro y ejecute algunos miles de iteraciones de cada versión y vea si hay una diferencia real. –

+0

¡Buena idea! Brb con los resultados ... – Moderator71

+4

¿Está tratando de resolver un problema de rendimiento real o simplemente está aburrido y jugando con micro optimizaciones que nunca representarán una diferencia significativa en una aplicación del mundo real? – JohnFx

Respuesta

11

Estoy de acuerdo con la respuesta de Kevin, definir variables en las que tienen significado. Preocuparse por las optimizaciones si y cuando se presentan y usted sabe que una declaración de variable es el problema. Sin embargo, tenga en cuenta los siguientes dos piezas de código

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); 
    } 
} 

y sus IL generada:

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 

ver ninguna diferencia? Esos chicos del compilador, son inteligentes.

+0

Usar el cronómetro no fue muy útil. Obtuve resultados variables, pero mirar el IL fue benéfico. Esencialmente, el compilador mueve la declaración a la parte superior del método dentro de la IL. Editaré mi publicación para proporcionar una aclaración de la IL. – Moderator71

2

me podría imaginar que el optimizador sabe que estos son los mismos y por lo tanto resultan tener el mismo rendimiento Sin embargo, puede que no. Puede inspeccionar el código o medida del objeto.

4

Ni. Todavía está creando una nueva cadena en cada iteración del ciclo, por lo que será la misma. Incluso si hay uno, lo que está tomando es increíblemente insignificante en el gran alcance de las cosas.

La declaración ámbito de la variable es lo que va a cambiar, y si no lo necesita fuera del bucle, a continuación, debe colocarlo en el interior.

Cuestiones relacionadas