2013-08-29 11 views
5

同僚と私はIfステートメントとそのパフォーマンスに関する意見が異なります。私の見解では、If...ElseIfステートメントを使用する必要があります。彼の見解では、ElseIfと信じておらず、ネストされたIfステートメントですべてを書きます。ネストした場合のElseステートメントとElseIfステートメントのパフォーマンスの相違

この場合、case文を使用できないとします。私が疑問に思っているのは、If..Elseステートメントと入れ子式If...ElseIfステートメントを使用して効率的にコードを実行する方法です。私は、コードの可読性が要因であることを知っていますが、パフォーマンスに影響を与えるべきではありません。

以下の例を見てみましょう。

もしそうでなければ使用:ElseIfステートメントを使用して

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 

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

私は、これは小規模な例ですが、このようなブロックは、アプリケーション全体で頻繁に使用されていると言うことができます知っています。

2つのコードセクションの間にパフォーマンスの違いはありますか?アプリケーションがコンパイルされるとほとんど同じ性能を発揮しますか?

#### UPDATE #####

私は倍の関数x番号を走るテストするためのプログラムを作成しました。

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 

私はプログラムを実行し、ここに私の結果は:
500ループの平均 - のElseIf:108.248msエルスの場合:106.507ms
千ループの平均 - のElseIf:107.747msエルスの場合:エルス107.451ms(もし最初の)
千ループの平均を実行している - のElseIf:107.683msエルスの場合:107.076ms(のElseIfは、最初の実行されている)

おそらく、数字が変化するであろう大きなデータセットと

が、これら3回の試験のうち、それが実際に表示されますIf Elseこと文はElseIfよりも優れています。

+7

何のパフォーマンスの違いは、単に読みやすさは、ありません... – dcro

+2

あなたは基本的に青や緑が...これは、パフォーマンスに影響を与えずに少しを持っている最高の色であるかどうかを議論しています。 – BentOnCoding

+0

drcoとBentOnCodingの両方に同意します。ねえ、あなたの同僚がRPSや手根管を望んでいるなら、是非、ElseIfを使わないでください。しかし、私はそれをお勧めしません(コードの明確性の理由 - 健康上の理由も悪くはありません;)) – fourpastmidnight

答えて

6

テストで広範囲にそれをすべてカバーし、独自の方法にそれらをリファクタリングしてみてください、それが思われます(ildasmを使用して)同じコードを生成すること。これは非常に単純なIf文で、異なるIfに対して異なる結果をもたらすかもしれません。私はあなたのコードで同じことをやってみることをお勧めします。

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 

そして、他の1

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 

私は読みやすいものを使用することをお勧めします。

+0

ありがとう、これは私が探していたものです。彼らは同じようにコンパイルするように見えるので、私は睡眠機能そのものではなく、ステートメントではないと思った違いを推測しています。 –

+1

@NicholasPost非常に高速なものをベンチマークすることは非常に困難です。多分、CPUは他のプロセスで少し忙しかったでしょう。 –

0

これはコードによって異なります。

if文は条件が満たされたときにのみアクセスされます。そうでない場合は無視されます。 if elseif elseブロックは同じですが、多くの条件をテストしており、どちらが満たされているかに応じて、必要な結果を得るために別のアクションを実行する必要があります。

私の意見は「それは場合によって異なります」です。

あなたは、その後のelseif使用し、あなたのコードのすべてを実行したい場合は...

あなたは私がその多くifelseif持っているとき

+0

私はElseIfステートメントを持っていれば、1つ上のほうが真実になってもそれぞれが評価されると言っていますか? –

+0

@NicholasPostパフォーマンスに違いはありません!彼らはまったく同じ状態をチェックします! –

0

は、私は常にスイッチケースを好む..場合は、何かの使用を無視したい場合は、しかし、私はそれが常に可能であることを知っています。その場合、ElseIfは常によく見え、else ifというバックグラウンドで実装されているので、同じパフォーマンスにする必要があります。

でも!私の同僚や上司の何人かを含む多くの人々のために、それはifififと読んでいるので、それは読みにくいです。

0

から来た同僚が、私は簡単なテストを実行し、のElseIfは、ネストされたIfよりも若干速く走ることを見つけたので、私は理解して....私はそれがクレイジーだ知っているが、それは私が考えるいくつかの心理学のことです。以下のコードを参照してください。

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

私はConsole.Writeでベンチマークをするのは良い考えだとは思わない。 –

+0

十分に良い。あなたが好きなコードでConsole.Writeを置き換えてください。 –

+0

出力を調整しますか? – Shoe

2

まあ、私はそれがすべてあなたが確認している条件に依存すると信じています。例えば

(擬似コード):

:この例では

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

、以下に再書き込みがおそらくより効率的であることを意味するすべてif文の間で共有される共通の条件があります

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

ただし、A条件の結果をキャッシュすると、パフォーマンスの向上はおそらく最小限に抑えられます。コンパイラによって実行されるの最適化さえあるかもしれないので、パフォーマンステストを実行して実行時間にも違いがあることを確認する必要があります。

さらに重要なことに、パフォーマンスクリティカルなコードを書く場合を除き、常に可読性に焦点を当ててコードを書くようにしてください。とにかく効率を損なうことなく、条件付きステートメントをフラット化する効率的な方法がほとんど常にあります。

+1

確かにコンパイラの最適化があります。結果をキャッシュするようなことを行うことは、場合によっては(例えば結果が非常に高価な場合など)良い戦略であるが、通常は必要ではない。書き込み、プロファイリング、チューニング(必要な場合)は、従う開発方法です – STW

3

あなたは間違ったことを心配しています!

あなたが書いたコードは、実行されるコードではありません。コンパイラは最適化のためにコードの構造を変更しますが、これは非常にうまくいきます。たとえそれが最適化を実行しなかったとしても、速度の差は問題ではないと言いました。

"それはできるだけ速いのですか?"と心配しないでください。代わりに、「それは十分に速く、維持可能(可読性)であるか」ということについて心配してください。

コンパイラとプロセッサは論理構造を理解するのに非常に優れていますが、meatbags(人)はそうではありません。コードを書くときはいつでも、それができるだけ親しみやすく、読みやすいものであることを確認してください。遅い場合は、読みやすさを犠牲にしてパフォーマンスを向上させることができますが、これを避けるためには「早すぎる最適化」と呼ばれ、コードを作成してバグを残すことはできません。多くのIFSと

  • 方法/よそそれはどの単一のメソッドは、この多くはないことを示し、彼らが高い「cyclomatic complexity」を持っている(コード-香りです:。とは言うものの、ここではいくつかのガイドラインだと

    あなたのメソッドをより多くの小さなメソッドに分解してください。あなたは何をすべきかを決定する比較的大きな "コントロール"メソッドで終わるかもしれませんが、実際にそれを行うというタスクを委譲します他の方法に

  • 可能な限りネスティングを減らしてください。

    単純なreturnが終了するか終了する場合は、 を試して、早い段階で確認してください(例:if (something) { return; })。

  • グループ関連のチェック一緒に、と

  • は、私は2つの逆コンパイルしまし

+0

私が聞いた質問は、読みやすさやできるだけ速くすることではなく、実際に実行に違いがあるかどうかを確認することです。私は物事の全体的なスキームにおいて、違いが顕著にならないか、または問題になるほど十分なパフォーマンスに影響しないこと、そして考えなければならない他の多くの要因があることに同意します。私はちょうど違いが何であるか私の個人的な知識(おそらくより深いコンピューティングのレベルで)を知りたい。 –

+2

あなたが尋ねた質問にはthe_lotusが答えました。the_lotusはおそらく代表的なケースを逆コンパイルし、同じコードが両方に対して生成されていることを発見しました。コンパイラが両方のイディオムで同じコードを*論理的に*同等の*ケースで出力した場合、テストを実行している間、システム上で起こっている何かの成果の違いが見えます。あなたの同僚がそれを理解していない場合(それは私には驚かないでしょう)、あなたはあなたに時間を浪費しています。 –

0

パフォーマンスの観点からは、意味のある違いはありません。私にとっては、ElseIfの可読性が明らかに優れています。

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 
関連する問題