2010-10-12 11 views
6

Czy szybciej jest zadeklarować zmienne w pętli lub poza pętlą? Na przykład:Szybciej deklarować zmienne w pętli lub poza pętlą?

' 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 

Który z nich jest szybszy? Czemu? Zakładam, że ta ostatnia jest szybsza, ponieważ jest to ponowne użycie tego samego "wskaźnika", aby odwoływać się do nowej wartości za kulisami zamiast tworzenia nowego wskaźnika w każdej iteracji, prawda? Czy ktoś może rozwinąć?

Dzięki

aktualizacja:

kompilator wystarczająco inteligentny, aby zoptymalizować kod podczas generowania Intermediate Language. Przenosi deklaracje zmiennych na górę metody. Poniżej jest declartions obrębie IL po kompilacji:

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

Oto cała IL dla zainteresowanych:

.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

Może kompilator zoptymalizuje go? Najlepsza rada: odpal IDE, stwórz stoper i uruchom kilka tysięcy powtórzeń każdej wersji i zobacz, czy jest jakaś prawdziwa różnica. –

+0

Dobry pomysł! Brb z wynikami .. – Moderator71

+4

Czy próbujesz rozwiązać rzeczywisty problem z wydajnością, czy po prostu jesteś znudzony i bawiąc się mikro-optymalizacjami, które nigdy nie będą stanowiły znaczącej różnicy w prawdziwym świecie aplikacji? – JohnFx

Odpowiedz

11

Zgadzam się z odpowiedzią Kevina, określ zmienne tam, gdzie mają one znaczenie. Martw się o optymalizacje, jeśli i kiedy się prezentują i wiesz, że problemem jest deklaracja zmienna. Jednak należy wziąć pod uwagę następujące dwa fragmenty kodu

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

i ich wygenerowany 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 

widzę żadnej różnicy? Ci kompilatorzy, są sprytni.

+0

Korzystanie ze stopera nie było zbyt przydatne. Mam różne wyniki, ale patrzenie na IL było korzystne. Zasadniczo kompilator przesuwa deklarację na górę metody w obrębie IL. Zmienię mój post, aby wyjaśnić IL. – Moderator71

2

mogę sobie wyobrazić, że optymalizator nie wie, że są takie same i dlatego okazują mieć taką samą wydajność. Może jednak nie. Możesz sprawdzić kod obiektu lub miarę.

4

Ani. Ciągle tworzysz nowy ciąg w każdej iteracji pętli, więc będą one takie same. Nawet jeśli taki istnieje, to, co robisz, jest niewiarygodne w szerokim zakresie rzeczy.

Deklaracja zakresu zmiennej jest tym, co się zmieni, a jeśli nie potrzebujesz jej poza pętlą, powinieneś umieścić ją w środku.

Powiązane problemy