7

巨大なDataTableがあり、各行を調べて特定の値を検証する必要があります。

IFELSEまたはSELECTCASEの構造で、パフォーマンスが向上するのはどちらの方法ですか?(私は私に最高のパフォーマンスを提供する方法に焦点を合わせています)

それ以外の場合(方法#1)

For Each vRow In vDTtemp.Rows
    If vRow("Item") = "Time" Then
        vRow("Result") = "000"
    ElseIf vRow("Item") = "DateTime" Then
        vRow("Result") = "001"
    ElseIf vRow("Item") = "String" Then
        vRow("Result") = "002"
    Else
        vRow("Result") = "N/A"
    End If
Next

ケースを選択(方法#2)

For Each vRow In vDTtemp.Rows
    Select Case vRow("Item")
        Case "Time"
            vRow("Result") = "000"
        Case "DateTime"
            vRow("Result") = "001"
        Case "String"
            vRow("Result") = "002"
        Case Else
            vRow("Result") = "N/A"
    End Select
Next
4

4 に答える 4

6

違いはありません。どちらのコードスタイルもまったく同じILを生成します。コンパイルされたアセンブリでildasm.exeツールを実行すると表示されます。

一般に、VB.NETコンパイラSelectステートメントを最適化するように努力します。これは、セレクターおよび簡単なCaseステートメントとして単純な値型を使用する場合に機能します。生成されたコードは、専用のIL命令Opcodes.Switchを使用します。これは、ルックアップテーブルを使用するマシンコードにコンパイルされます。とても早い。

ただし、文字列式をセレクターとして使用する場合は機能しません。そのルックアップテーブルを作成するには、デリゲートのディクショナリに相当するものが必要になります。これはあまりにも影響力があり、コンパイラは各caseステートメントをIfステートメントと同等のものに変換する以外に何もできません。ただし、コードにこの辞書を作成することで、自分で簡単に最適化できます。辞書のキーと値は単純な文字列であるため、簡単に実行できます。十分なケースがなく、文字列が短すぎて、これを大いに成果を上げることはできませんが、試してみる価値はあります。それは確かにあなたのコードを圧縮することができます。

于 2013-02-28T21:04:22.030 に答える
6

私は過去数日間、この同じ問題にかなりの時間を費やしてきましたが、他のアプローチよりもはるかに高速なアプローチを見つけました。文字列変数でSelectCaseを使用することは、一連のIf / Else Ifステートメントと同等であり、どちらもがっかりするほど遅いこともわかりました。

ただし、次の手法は非常にうまく機能し、時間を50%以上短縮しました。元のコードの代わりに:

For Each vRow In vDTtemp.Rows
    Select Case vRow("Item")
        Case "Time"
            vRow("Result") = "000"
        Case "DateTime"
            vRow("Result") = "001"
        Case "String"
            vRow("Result") = "002"
        Case Else
            vRow("Result") = "N/A"
    End Select
Next

単純なブール値をオンに切り替えるように変更し、次のようにString.Equalsメソッドを使用します。

For Each vRow In vDTtemp.Rows
    'Read out the row value so we only need to access the datarow once
    rowValue = vRow("Item")
    'Which of these statements is true?
    Select Case True
        Case rowValue.Equals("Time")
            vRow("Result") = "000"
        Case rowValue.Equals("DateTime")
            vRow("Result") = "001"
        Case rowValue.Equals("String")
            vRow("Result") = "002"
        Case Else
            vRow("Result") = "N/A"
    End Select
Next

このようにアプローチすることで大幅な改善が見られました。ある場合には、コードを100,000回の反復ループでの1.3秒から0.5秒に短縮しました。これがコードの非常に頻繁に呼び出されるタイムクリティカルセクションにある場合、それは大きな違いを生む可能性があります。

ただし、以下のコメントで指摘されているように、これは文字列の「序数」比較を実行します。これは、英語以外のロケールが使用されている場合、期待される動作をもたらさない可能性があります(例についてはコメントを参照)。

アダム。

于 2013-11-20T14:18:22.263 に答える
5

わかりました...この投稿はかなり前のことですが、今は同じ質問を検索していて、これに新しい最適化を追加できます。今のところ、読みやすくするために、selectcaseを使用することを選択しました。一方、「Dim」がfor-nextループ内にある場合、パフォーマンスは大幅に低下します。

     For Each vRow In vDTtemp.Rows
------->  Dim rowItem = vRow("Item")
        If rowItem = "Time" Then
            vRow("Result") = "000"
        ElseIf rowItem = "DateTime" Then
            vRow("Result") = "001"
        ElseIf rowItem = "String" Then
            vRow("Result") = "002"
        Else
            vRow("Result") = "N/A"
        End If
    Next

if-then構造を使用する場合でも、dimがoitsideの場合は、はるかに高速です。

------->     Dim rowItem as string
             For Each vRow In vDTtemp.Rows
------->            rowitem= vRow("Item")
                If rowItem = "Time" Then
                    vRow("Result") = "000"
                ElseIf rowItem = "DateTime" Then
                    vRow("Result") = "001"
                ElseIf rowItem = "String" Then
                    vRow("Result") = "002"
                Else
                    vRow("Result") = "N/A"
                End If
            Next

これがもっと誰かに役立つことを願っています;)

于 2016-02-01T15:47:03.993 に答える
2

これがパフォーマンスのボトルネックであることが本当にわかった場合は、次のようにIf..Then句を変更して、インデクサーに1回だけアクセスしてみてください。

For Each vRow In vDTtemp.Rows
    Dim rowItem = vRow("Item")
    If rowItem = "Time" Then
        vRow("Result") = "000"
    ElseIf rowItem = "DateTime" Then
        vRow("Result") = "001"
    ElseIf rowItem = "String" Then
        vRow("Result") = "002"
    Else
        vRow("Result") = "N/A"
    End If
Next

そうは言っても、私はこれらのそれぞれが過剰最適化のケースであると思います。コンパイラはここで最善を尽くす必要があります。長いSelectCaseからILをチェックすると、残りの句をエスケープするために、カバーの下に「goto」が付いたIf..then句の文字列が使用されていることがわかります。ここでの最善のオプションは、最も保守しやすいコードを取得することです。これは、得られる可能性のあるパフォーマンス上の利点が、if..thenとselectcaseの間に見られる最小限のブーストによって相殺されるためです。

于 2013-02-28T21:00:53.837 に答える