6

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

この状況では case ステートメントを使用できないと仮定しましょう。私が疑問に思っているのは、ステートメントを使用する場合If..Elseと比べて、ネストされたステートメントを使用してコードを効率的に実行することIf...ElseIfです。コードの読みやすさが要因であることは知っていますが、パフォーマンスに影響を与えるべきではありません。

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

If 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 の使用:

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

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

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

####アップデート#####

関数を 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 If Else: 106.507ms
1000 ループ平均 - ElseIf: 107.747ms If Else: 107.451ms (Else If running first)
1000 ループ平均 - ElseIf: 107.683ms If Else: 107.076ms (ElseIf が最初に実行されます)

おそらく、より大きなデータセットでは数値が変わるでしょうが、これらの 3 回の試行のうち、実際にはステートメントIf Elseよりも優れているように見えます.ElseIf

4

7 に答える 7

8

私は 2 つを逆コンパイルしましたが、同じコードを生成しているようです (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

そしてもう一つ

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

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

于 2013-08-29T13:50:35.723 に答える
7

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

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

「それは可能な限り速いですか?」と心配する必要はありません。代わりに、「十分に高速で、可能な限り保守可能 (読み取り可能) か?」について心配してください。

コンパイラとプロセッサは論理構造を理解するのが得意ですが、ミートバッグ (人) はそうではありません。コードを書くときはいつでも、できるだけ親しみやすく読みやすいものにするように努めるべきです。容認できないほど遅いことがわかった場合は、パフォーマンスのために可読性を犠牲にすることができますが、パラノイアからそうするのは「時期尚早の最適化」と呼ばれ、保守不可能な (そして最終的にはバグを生み出す) コードを作成するための優れた方法です。

そうは言っても、ここにいくつかのガイドラインがあります:

  • 多くの ifs/else を含むメソッドはコードの匂いがします (「循環的複雑度」が高くなります。これは、単一のメソッドが多くのことを行っていることを示しており、そのため、読み取り、保守、テスト、および変更が難しくなっています。メソッドを多数に分解してください。より小さなメソッド. 何をすべきかを決定する比較的大きな「制御」メソッドで終わるかもしれませんが、実際にそれを行うタスクを他のメソッドに委譲します.

  • ネスティングをできるだけ減らします。

    シンプルまたは終了になるケースがある場合returnは、シーケンスの早い段階でそれらをチェックしてみてください: (例: if (something) { return; })。

  • 関連するチェックをグループ化し、それらを独自の方法にリファクタリングしてみてください

  • テストですべてを広範囲にカバー

于 2013-08-29T13:26:39.153 に答える