Faster to declare variables inside a loop or outside a loop?
Is it faster to declare variables inside a loop or outside a loop? For example:
' 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
Which one is faster? Why? I assume the latter is faster because it is just reusing the same "pointer" to reference a new value behind the scenes instead of creating a new pointer each iteration, correct? Can someone elaborate?
Thanks
Updated:
The Compiler is intelligent enough to optimize the code when generating the Intermediate Language. It moves the variable declarations to the top of the method. Below, is the declartions within the IL after compilation:
.locals init ([0] string newVariable2,
[1] int32 i,
[2] string newVariable,
[3] int32 V_3,
[4] int32 VB$CG$t_i4$S0)
Here's the entire IL for those interested:
.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开发者_Go百科_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
I agree with Kevin's answer, define variables where they have meaning. Worry about optimizations if and when they present themselves and you know that a variable declaration is the issue. However, consider the following two pieces of code
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);
}
}
And their generated 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
See any difference? Those compiler guys, they're smart.
Neither. You are still creating a new string in each iteration of the loop, so they will be the same. Even if there is one, what you are taking about is unbelievable negligible in the big scope of things.
The scope declaration of the variable is what will change, and if you don't need it outside of the loop, then you should place it inside.
I could imagine that the optimizer knows that these are the same and therefore they turn out to have the same performance. It might not though. You could either inspect the object code or measure.
精彩评论