2013-08-29 7 views
5

Ein Mitarbeiter und ich haben unterschiedliche Meinungen über If Aussagen und ihre Leistung. Meine Ansicht ist, dass If...ElseIf Aussagen verwendet werden sollten. Seine Ansicht ist, dass er nicht glaubt in ElseIf, und schreibt alles mit verschachtelten If Aussagen.Leistungsunterschiede von verschachtelten wenn Else-Anweisungen vs. ElseIf-Anweisungen

Angenommen, eine case-Anweisung kann in dieser Situation nicht verwendet werden. Was ich frage mich ist, wie effizient Code mit verschachtelten If..Else Aussagen im Vergleich zu If...ElseIf Anweisungen ausgeführt wird. Ich weiß, dass die Lesbarkeit von Code ein Faktor ist, aber das sollte die Leistung nicht beeinträchtigen.

Schauen wir uns die folgenden Beispiele an.

verwenden Wenn Else:

If() then 
    'Do something' 
Else 
    If() then 
     'Do something' 
    Else 
     If() then 
      'Do something' 
     Else 
      If() then 
       'Do something' 
      Else 
       'Do something else' 
      End If 
     End If 
    End If 
End If 

ElseIf Verwendung:

If() then 
    'Do something' 
ElseIf() then 
    'Do something' 
ElseIf() then 
    'Do something' 
ElseIf() then 
    'Do something' 
Else 
    'Do something else' 
End If 

Ich weiß, das ist ein kleines Beispiel, läßt aber wie diese Blöcke sagen, sind stark in der gesamten Anwendung verwendet.

Gibt es Leistungsunterschiede zwischen den beiden Codeabschnitten oder würden sie fast identisch funktionieren, sobald die Anwendung kompiliert wurde?

#### UPDATE #####

habe ich ein Programm zu testen, die Funktionen x Anzahl der Laufzeiten durch.

Public Class Form1 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
    For i As Integer = 0 To 1000 
     Run() 
    Next 
End Sub 

Sub Run() 

    Dim Time1Start As Integer = 0 
    Dim Time1End As Integer = 0 
    Dim Time2Start As Integer = 0 
    Dim Time2End As Integer = 0 

    Time2Start = CInt(DateTime.Now.ToString("fff")) 
    runElse() 
    Time2End = CInt(DateTime.Now.ToString("fff")) 

    Time1Start = CInt(DateTime.Now.ToString("fff")) 
    runElseIf() 
    Time1End = CInt(DateTime.Now.ToString("fff")) 

    TextBox1.Text += If(Time1End < Time1Start, Time1End + (1000 - Time1Start), Time1End - Time1Start) & vbTab & If(Time2End < Time2Start, Time2End + (1000 - Time2Start), Time2End - Time2Start) & vbCrLf 
End Sub 

Sub runElseIf() 
    If sleep(10) Then 
     'Do something' 
    Else 
     If sleep(10) Then 
      'Do something' 
     Else 
      If sleep(10) Then 
       'Do something' 
      Else 
       If sleep(10) Then 
        'Do something' 
       Else 
        If sleep(10) Then 
         'Do something' 
        Else 
         If sleep(10) Then 
          'Do something' 
         Else 
          If sleep(10) Then 
           'Do something' 
          Else 
           If sleep(10) Then 
            'Do something' 
           Else 
            If sleep(10) Then 
             'Do something' 
            Else 
             If sleep(10) Then 
              'Do something' 
             Else 
              'Do something else' 
             End If 
            End If 
           End If 
          End If 
         End If 
        End If 
       End If 
      End If 
     End If 
    End If 
End Sub 

Sub runElse() 
    If sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    ElseIf sleep(10) Then 
     'Do something' 
    Else 
     'Do something else' 
    End If 
End Sub 

Function sleep(ByVal ms As Integer) As Integer 
    System.Threading.Thread.Sleep(ms) 
    Return False 
End Function 

End Class 

ich das Programm lief und hier sind meine Ergebnisse:
500 Loops Durchschnitt - ElseIf: 108.248ms Wenn Else: 106.507ms
1000 Loops Average - ElseIf: 107.747ms Wenn Else: 107.451ms (Else If laufen zuerst)
1000 Loops Average - ElseIf: 107.683ms Wenn Else: 107.076ms (ElseIf

vielleicht mit einem größeren Datum ändern würden die Zahlen gesetzt zuerst) ausgeführt wird, aber aus diesen drei Studien scheint es tatsächlich, dass die If Else übertrifft die ElseIf Aussagen.

+7

Es gibt keine Leistungsunterschiede sind nur Lesbarkeit ... – dcro

+2

Sie streiten sich grundsätzlich, ob blau oder grün die beste Farbe ist ... Dies muss ohne Auswirkungen auf die Leistung wenig. – BentOnCoding

+0

Ich stimme sowohl drco als auch BentOnCoding zu. Hey, wenn dein Kollege RPS oder Karpaltunnel haben will, benutze auf keinen Fall 'ElseIf'. Aber ich würde es nicht empfehlen (aus Gründen der Code-Klarheit - obwohl auch Gesundheitsgründe nicht schlecht sind;)) – fourpastmidnight

Antwort

6

ich die beiden dekompilierten habe und es scheint den gleichen Code erzeugen (mit ildasm). Dies ist eine sehr einfache If-Anweisung, die für unterschiedliche If möglicherweise ein anderes Ergebnis liefert. Ich würde vorschlagen, dass Sie dasselbe mit Ihrem Code tun und sehen.

Module Module1 

    Sub Main() 

     Dim a As Integer 
     Dim i As Integer = 1 

     If i = 1 Then 
      a = 9 
     ElseIf i = 2 Then 
      a = 8 
     ElseIf i = 3 Then 
      a = 7 
     Else 
      a = 6 
     End If 

    End Sub 

End Module 



.method public static void Main() cil managed 
{ 
    .entrypoint 
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = (01 00 00 00) 
    // Code size  30 (0x1e) 
    .maxstack 2 
    .locals init ([0] int32 a, 
      [1] int32 i) 
    IL_0000: ldc.i4.1 
    IL_0001: stloc.1 
    IL_0002: ldloc.1 
    IL_0003: ldc.i4.1 
    IL_0004: bne.un.s IL_000b 
    IL_0006: ldc.i4.s 9 
    IL_0008: stloc.0 
    IL_0009: br.s  IL_001d 
    IL_000b: ldloc.1 
    IL_000c: ldc.i4.2 
    IL_000d: bne.un.s IL_0013 
    IL_000f: ldc.i4.8 
    IL_0010: stloc.0 
    IL_0011: br.s  IL_001d 
    IL_0013: ldloc.1 
    IL_0014: ldc.i4.3 
    IL_0015: bne.un.s IL_001b 
    IL_0017: ldc.i4.7 
    IL_0018: stloc.0 
    IL_0019: br.s  IL_001d 
    IL_001b: ldc.i4.6 
    IL_001c: stloc.0 
    IL_001d: ret 
} // end of method Module1::Main 

Und die anderen

Module Module1 

    Sub Main() 

     Dim a As Integer 
     Dim i As Integer = 1 

     If i = 1 Then 
      a = 9 
     Else 
      If i = 2 Then 
       a = 8 
      Else 
       If i = 3 Then 
        a = 7 
       Else 
        a = 6 
       End If 
      End If 
     End If 

    End Sub 

End Module 

.method public static void Main() cil managed 
{ 
    .entrypoint 
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = (01 00 00 00) 
    // Code size  30 (0x1e) 
    .maxstack 2 
    .locals init ([0] int32 a, 
      [1] int32 i) 
    IL_0000: ldc.i4.1 
    IL_0001: stloc.1 
    IL_0002: ldloc.1 
    IL_0003: ldc.i4.1 
    IL_0004: bne.un.s IL_000b 
    IL_0006: ldc.i4.s 9 
    IL_0008: stloc.0 
    IL_0009: br.s  IL_001d 
    IL_000b: ldloc.1 
    IL_000c: ldc.i4.2 
    IL_000d: bne.un.s IL_0013 
    IL_000f: ldc.i4.8 
    IL_0010: stloc.0 
    IL_0011: br.s  IL_001d 
    IL_0013: ldloc.1 
    IL_0014: ldc.i4.3 
    IL_0015: bne.un.s IL_001b 
    IL_0017: ldc.i4.7 
    IL_0018: stloc.0 
    IL_0019: br.s  IL_001d 
    IL_001b: ldc.i4.6 
    IL_001c: stloc.0 
    IL_001d: ret 
} // end of method Module1::Main 

Ich würde vorschlagen, die man verwenden, die leichter zu lesen ist.

+0

Danke dafür, es ist genau das, was ich gesucht habe. Da sie scheinbar das gleiche kompilieren, vermute ich, dass Unterschiede, die ich gesehen habe, auf die Schlaffunktion selbst und nicht auf die Anweisungen zurückzuführen sind. –

+1

@NicholasPost Es ist sehr schwierig, sehr schnelle Dinge zu vergleichen. Vielleicht war die CPU ein bisschen beschäftigt mit einem anderen Prozess. –

0

Es hängt von Ihrem Code ab.

Auf die if-Anweisung wird nur zugegriffen, wenn eine Bedingung erfüllt ist, andernfalls wird sie ignoriert. Der if elsef else Block ist derselbe, testet jedoch für viele Bedingungen und abhängig davon, welche erfüllt ist, muss möglicherweise eine andere Aktion ausgeführt werden, um die gewünschten Ergebnisse zu erhalten.

Meine Meinung ist "Es kommt auf Fälle an".

Wenn Sie alles in Ihrem Code auszuführen, dann elseif verwenden ..

wenn Sie etwas Gebrauch zu ignorieren, wenn ..

+0

Also sagst du, dass, wenn ich habe und ElseIf Aussage, dass jeder ausgewertet wird, auch wenn man höher wahr wird? –

+0

@NicholasPost gibt es keinen Unterschied in den Leistungen! sie prüfen genau den gleichen Zustand! –

0

i immer Schaltergehäuse vorziehen, wenn ich, dass viele ifelseif haben, aber ich weiß, dass es immer möglich ist. in diesem Fall sieht die ElseIf immer besser aus, und ist im Hintergrund mit else if implementiert, so sollte es die gleichen Leistungen sein.

aber! für viele Leute, einschließlich einiger meiner Kollegen und Chefs, ist es nicht lesbar, weil es als ififif gelesen wird. Ich weiß, dass es verrückt ist, aber es ist etwas Psychologie Sache, die ich denke .... so verstehe ich, wo Ihre Mitarbeiter kommen aus

0

Ich lief einen schnellen Test und fand, dass ElseIf läuft etwas schneller als verschachtelt, wenn. Siehe den folgenden Code.

Imports System.Diagnostics 
Module Module1 

    Sub Main() 
     Dim sw As New Stopwatch() 
     Dim nestedTotal As Integer 
     sw.Start() 
     For i = 1 To 100000 
      Nested() 
     Next 
     sw.Stop() 
     nestedTotal = sw.ElapsedMilliseconds 

     sw.Reset() 

     Dim elsesTotal As Integer 
     sw.Start() 
     For i = 1 To 100000 
      Elses() 
     Next 
     sw.Stop() 
     elsesTotal = sw.ElapsedMilliseconds 
     Console.WriteLine("Nested If:" & nestedTotal) 
     Console.WriteLine("ElseIf:" & elsesTotal) 
     Console.Read() 
    End Sub 

    Sub Nested() 
     Dim num As Integer = GetNum() 
     If num = 1 Then 
      DoSomething() 
     Else 
      If num = 2 Then 
       DoSomething() 
      Else 
       If num = 3 Then 
        DoSomething() 
       Else 
        If num = 4 Then 
         DoSomething() 
        Else 
         DoSomething() 
        End If 
       End If 
      End If 
     End If 
    End Sub 

    Sub DoSomething() 
     Dim j As Integer 
     For i = 1 To 1000 
      j = i + j 
     Next 
    End Sub 

    Sub Elses() 
     Dim num As Integer = GetNum() 
     If num = 1 Then 
      DoSomething() 
     ElseIf num = 2 Then 
      DoSomething() 
     ElseIf num = 3 Then 
      DoSomething() 
     ElseIf num = 4 Then 
      DoSomething() 
     Else 
      DoSomething() 
     End If 
    End Sub 

    Function GetNum() 
     Dim Generator As System.Random = New System.Random() 
     Return Generator.Next(1, 5) 
    End Function 
End Module 
+1

Ich glaube nicht, Benchmarking mit Console.Write ist eine gute Idee. –

+0

Fair genug. Ersetzen Sie Console.Write mit dem Code, den Sie mögen. –

+0

Wheres die Ausgabe? – Shoe

2

Nun, ich glaube, es hängt alles von den Bedingungen ab, die Sie überprüfen.

Zum Beispiel (Pseudocode):

if (A && B) { 
} elseif (A && C) { 
} elseif (A && D) { 
} 

In diesem Beispiel ist es ein gemeinsamer zwischen allen if Aussagen gemeinsamen Zustand, was bedeutet, dass die folgende Umschreiben wahrscheinlich ist effizienter:

if (A) { 
    if (B) { 
    } elseif (C) { 
    } elseif (D) { 
    } 
} 

Allerdings, wenn Sie das Ergebnis der A Bedingung zwischenspeichern. Die Leistungssteigerungen wären wahrscheinlich minimal. Vielleicht gibt es sogar Optimierungen durch den Compiler durchgeführt, so dass Sie einen Leistungstest ausführen müssen, um sicherzustellen, dass es sogar einen Unterschied in der Ausführungszeit gibt.

Noch wichtiger ist, dass Sie, wenn Sie keinen leistungskritischen Code schreiben, immer versuchen, Code zu schreiben, indem Sie sich auf die Lesbarkeit konzentrieren. Es gibt fast immer einen effizienten Weg, konditionelle Aussagen zu vereinfachen, ohne die Effizienz zu beeinträchtigen.

+1

Es gibt definitiv Compiler-Optimierungen; Dinge wie Zwischenspeichern von Ergebnissen ist in einigen Fällen eine gute Strategie (z. B. wenn das Ergebnis sehr teuer ist), wird aber normalerweise nicht benötigt. Schreiben, Profilieren, Tuning (wenn nötig) ist die Entwicklungsmethodik, die zu befolgen ist – STW

3

Sie machen sich Sorgen wegen der falschen Dinge !!!

Der Code, den Sie schreiben, ist nicht der Code, der ausgeführt wird. Der Compiler ändert die Struktur Ihres Codes für die Optimierung, und es funktioniert sehr gut mit solchen Dingen. Das heißt, selbst wenn es keine Optimierungen durchführen würde, würde der Geschwindigkeitsunterschied keine Rolle spielen.

Mach dir keine Sorgen über "ist es so schnell wie es sein kann?" Sorgen Sie sich stattdessen "ist es schnell genug, und so gut wie möglich (lesbar)?".

Compiler und Prozessoren sind sehr gut darin, logische Strukturen zu verstehen, aber Meatbags (Menschen) sind nicht. Wenn Sie Code schreiben, sollten Sie sicherstellen, dass er so zugänglich und lesbar wie möglich ist. Wenn Sie feststellen, dass es nicht langsam ist, dann können Sie die Lesbarkeit für die Leistung opfern - aber Paranoia wird als "vorzeitige Optimierung" bezeichnet, und es ist eine gute Möglichkeit, Code zu machen, der nicht mehr zu halten ist (und eventuell Fehler erzeugt).

Mit dieser sagte, hier einige Richtlinien:.

  • Methoden mit vielen ifs/elses sind ein Code-Geruch (sie haben eine hohe „cyclomatic complexity“ Es zeigt an, dass eine einzelne Methode tut dies viele, die es macht es schwer zu lesen, zu warten, zu testen und zu verändern Zerlege deine Methode in viele kleinere Methoden Du wirst vielleicht noch eine relativ große "Kontroll" -Methode haben, die bestimmt, was zu tun ist - aber die Aufgabe delegieren zu anderen Methoden.

  • Reduzieren Sie die Verschachtelung so weit wie möglich.

    Wenn es Fälle gibt, die zu einem einfachen return führen oder den Ausgang verlassen, versuchen Sie , sie früh in der Reihenfolge zu überprüfen: (z. B. if (something) { return; }).

  • Gruppe bezogenen Prüfungen zusammen, und versuchen, sie auf ihre eigene Methode, um Refactoring

  • es decken alle ausführlich in Tests

+0

Die Frage, die ich gestellt habe, ist nicht die Lesbarkeit oder die Schnelligkeit, sondern nur, um zu sehen, ob tatsächlich Unterschiede in der Ausführung bestehen.Ich stimme zu, dass der Unterschied in der Gesamtstruktur der Dinge nicht spürbar ist oder die Leistung nicht ausreichend beeinflusst, um ein Problem zu werden, und dass es viele andere Faktoren gibt, an die man denken kann. Ich möchte nur für mein persönliches Wissen wissen (vielleicht auf einer tieferen Ebene der EDV), was die Unterschiede sind. –

+2

Die Frage, die Sie gestellt haben, wird von the_lotus beantwortet, der einen vermutlich repräsentativen Fall dekompiliert und festgestellt hat, dass der gleiche Code für beide generiert wurde - und Sie vorgeschlagen haben, dasselbe mit einem tatsächlichen Fall aus Ihrem eigenen Code zu tun. Wenn der Compiler den gleichen Code für * logisch * * äquivalente * Fälle in beiden Idiomen ausgibt, ist jeder scheinbare Leistungsunterschied ein Artefakt von etwas anderem, das auf dem System während des Tests auftritt. Wenn Ihr Mitarbeiter das nicht versteht (was mich nicht überraschen würde), dann verschwenden Sie Ihre Zeit damit, überhaupt mit ihm zu reden. –

0

Aus Leistungsperspektive gibt es keinen sinnvollen Unterschied. Für mich ist die Lesbarkeit des ElseIf deutlich besser.

Private Sub xelseif(tries As Integer) 
    Dim foo As Integer 
    For x As Integer = 1 To tries 
     For y As Integer = 1 To 5 Step 4 
      If y = 1 Then 
       foo = y 
      ElseIf y = 2 Then 
      ElseIf y = 3 Then 
      ElseIf y = 4 Then 
      ElseIf y = 5 Then 
       foo = y 
      End If 
     Next 
    Next 
End Sub 

Private Sub xelse(tries As Integer) 
    Dim foo As Integer 
    For x As Integer = 1 To tries 
     For y As Integer = 1 To 5 Step 4 
      If y = 1 Then 
       foo = y 
      Else 
       If y = 2 Then 
       Else 
        If y = 3 Then 
        Else 
         If y = 4 Then 
         Else 
          If y = 5 Then 
           foo = y 
          End If 
         End If 
        End If 
       End If 
      End If 
     Next 
    Next 
End Sub 

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    Dim stpw As New Stopwatch 
    Dim tries As Integer = 1500000 

    xelse(10) 
    stpw.Restart() 
    xelse(tries) 
    stpw.Stop() 
    Debug.WriteLine(stpw.ElapsedMilliseconds) 

    xelseif(10) 
    stpw.Restart() 
    xelseif(tries) 
    stpw.Stop() 
    Debug.WriteLine(stpw.ElapsedMilliseconds) 
End Sub 
Verwandte Themen