C#のswitchステートメントとCILのswitch命令を混同しないようにすることが重要です。
CILスイッチはジャンプテーブルであり、ジャンプアドレスのセットへのインデックスが必要です。
これは、C#スイッチのケースが隣接している場合にのみ役立ちます。
case 3: blah; break;
case 4: blah; break;
case 5: blah; break;
しかし、そうでなければほとんど役に立ちません:
case 10: blah; break;
case 200: blah; break;
case 3000: blah; break;
(必要なスロットは3つだけで、テーブルには最大3000エントリが必要です)
隣接しない式を使用すると、コンパイラーは線形if-else-if-elseチェックの実行を開始します。
隣接していない式セットが大きい場合、コンパイラはバイナリツリー検索で始まり、最後にif-else-if-elseで最後のいくつかの項目が検索されます。
隣接するアイテムの集まりを含む式セットを使用すると、コンパイラはバイナリツリー検索を実行し、最後にCILスイッチを実行できます。
これは「mays」と「mights」でいっぱいで、コンパイラに依存します(MonoまたはRotorとは異なる場合があります)。
隣接するケースを使用して私のマシンに結果を複製しました:
10ウェイスイッチを実行する合計時間、10000回の反復(ms):25.1383
10ウェイスイッチあたりの概算時間(ms):0.00251383
50ウェイスイッチを実行する合計時間、10000回の反復(ミリ秒):26.593
50ウェイスイッチあたりの概算時間(ミリ秒):0.0026593
5000ウェイスイッチを実行する合計時間、10000回の反復(ms):23.7094
5000ウェイスイッチあたりの概算時間(ms):0.00237094
50000ウェイスイッチを実行する合計時間、10000反復(ミリ秒):
50000ウェイスイッチあたりの概算時間20.0933 (ミリ秒):0.00200933
次に、隣接しないcase式も使用しました。
10ウェイスイッチを実行する合計時間、10000回の反復(ミリ秒):19.6189
10ウェイスイッチあたりの概算時間(ミリ秒):0.00196189
500ウェイスイッチを実行する合計時間、10000回の反復(ミリ秒):19.1664
500ウェイスイッチあたりの概算時間(ミリ秒):0.00191664
5000ウェイスイッチを実行する合計時間、10000回の反復(ミリ秒):
5000ウェイスイッチあたりの概算時間(ms):19.5871:0.00195871
隣接していない50,000ケーススイッチステートメントはコンパイルされません。
「式が長すぎるか複雑すぎて、 'ConsoleApplication1.Program.Main(string [])'の近くでコンパイルできません。
ここで面白いのは、バイナリツリー検索がCILスイッチ命令よりも(おそらく統計的には)少し高速に表示されることです。
ブライアン、あなたは「定数」という言葉を使いました。これは、計算の複雑さの理論の観点から非常に明確な意味を持っています。単純な隣接整数の例では、O(1)(定数)と見なされるCILが生成される可能性がありますが、まばらな例はO(log n)(対数)、クラスター化された例はその中間にあり、小さな例はO(n)(線形)です)。
これは、静的Generic.Dictionary<string,int32>
が作成される可能性があるStringの状況にも対応しておらず、最初の使用時に明確なオーバーヘッドが発生します。ここでのパフォーマンスは、のパフォーマンスに依存しGeneric.Dictionary
ます。
(CIL仕様ではなく)C#言語仕様を確認すると、「15.7.2 switchステートメント」で「一定の時間」について言及されていないか、基になる実装がCIL switch命令を使用していることもわかります(想定に十分注意してください)そのようなもの)。
結局のところ、現代のシステムでの整数式に対するC#の切り替えはサブマイクロ秒の操作であり、通常は心配する必要はありません。
もちろん、これらの時間はマシンと条件に依存します。私はこれらのタイミングテストに注意を払いません、私たちが話しているマイクロ秒の持続時間は、実行されている「実際の」コードによって小さくなります(そして、いくつかの「実際のコード」を含める必要があります。そうしないと、コンパイラがブランチを最適化します)。システムのジッタ。私の回答は、IL DASMを使用して、C#コンパイラーによって作成されたCILを調べることに基づいています。もちろん、これは最終的なものではありません。CPUが実行する実際の命令は、JITによって作成されるためです。
x86マシンで実際に実行された最終的なCPU命令を確認しました。次のような単純な隣接セットスイッチを確認できます。
jmp ds:300025F0[eax*4]
二分木検索は以下でいっぱいです:
cmp ebx, 79Eh
jg 3000352B
cmp ebx, 654h
jg 300032BB
…
cmp ebx, 0F82h
jz 30005EEE