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 スイッチを実行する場合があります。
これは「可能性」と「可能性」でいっぱいで、コンパイラに依存します (Mono または Rotor と異なる場合があります)。
隣接するケースを使用して、マシンで結果を複製しました。
10 方向の切り替えを実行する合計時間、10000 回の反復 (ms) : 25.1383
10 方向の切り替えあたりのおおよその時間 (ms) : 0.00251383
50 方向の切り替えを実行する合計時間、10000 回の反復 (ms) : 26.593
50 方向の切り替えあたりのおおよその時間 (ms) : 0.0026593
5000 通りの切り替え、10000 回の反復を実行する合計時間 (ms) : 23.7094
5000 通りの切り替えあたりのおおよその時間 (ms) : 0.00237094
50000 通りの切り替えを実行する合計時間、10000 回の反復 (ms) : 20.0933
50000 通りの切り替えあたりのおおよその時間 (ms) : 0.00200933
次に、隣接しないケース式も使用しました。
10 方向の切り替えを実行する合計時間、10000 回の反復 (ms) : 19.6189
10 方向の切り替えあたりのおおよその時間 (ms) : 0.00196189
500 通りの切り替えを実行する合計時間、10000 回の反復 (ms) : 19.1664
500 通りの切り替えあたりのおおよその時間 (ms) : 0.00191664
5000 通りの切り替え、10000 回の反復を実行する合計時間 (ms) : 19.5871
5000 通りの切り替えあたりのおおよその時間 (ms) : 0.00195871
隣接していない 50,000 ケースの switch ステートメントはコンパイルされません。
「式が長すぎるか複雑すぎて、'ConsoleApplication1.Program.Main(string[])' の近くでコンパイルできません。
ここで面白いのは、二分木検索が CIL switch 命令よりも少し (おそらく統計的にではなく) 速く表示されることです。
ブライアン、あなたは「定数」という言葉を使いましたが、これは計算複雑性理論の観点から非常に明確な意味を持っています。単純な隣接整数の例では、O(1) (定数) と見なされる CIL が生成される可能性がありますが、疎な例は O(log n) (対数) であり、クラスター化された例はその中間にあり、小さな例は O(n) (線形) です。 )。
これは、静的Generic.Dictionary<string,int32>
が作成される可能性がある文字列の状況にも対応しておらず、最初の使用時に明確なオーバーヘッドが発生します。ここでのパフォーマンスは のパフォーマンスに依存しますGeneric.Dictionary
。
C# 言語仕様(CIL 仕様ではありません) を確認すると、「15.7.2 The switch ステートメント」で「一定時間」について言及されていないか、基になる実装で CIL スイッチ命令が使用されていることさえわかります (仮定には十分注意してください)。そのようなこと)。
結局のところ、最新のシステムでの整数式に対する C# の切り替えは、1 マイクロ秒未満の操作であり、通常は心配する必要はありません。
もちろん、これらの時間はマシンと条件によって異なります。これらのタイミング テストには注意を払いません。ここで話しているマイクロ秒の期間は、実行中の「実際の」コードよりも小さくなります (「実際のコード」を含める必要があります。そうしないと、コンパイラが分岐を最適化してしまいます)。システムのジッタ。私の答えは、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