switch on string と elseif on type はどちらが速いか?
質問
文字列の比較に基づいて取るべきコードパスを特定するオプションがあるとしましょうか、さもなければ型をiffingします。
どちらがより速いですか、そしてそれはなぜですか?
switch(childNode.Name)
{
case "Bob":
break;
case "Jill":
break;
case "Marko":
break;
}
if(childNode is Bob)
{
}
elseif(childNode is Jill)
{
}
else if(childNode is Marko)
{
}
更新しました。 私がこれを尋ねる主な理由は、switch文がケースとしてカウントされるものについて独特であるためです。たとえば、それは変数の使用を許可しませんが、メイン アセンブリに移動される定数だけは許可します。私は、switch文がおかしなことをするために、このような制限があるのだと思いました。もしそれが elseif にのみ変換されるのであれば (ある投稿者がコメントしたように)、なぜ case 文で変数を許可されないのでしょうか?
洞窟。
後最適化をしています。このメソッドは
多く
回呼び出されます。
どのように解決するのですか?
Greg のプロファイルの結果は、彼がカバーした正確なシナリオでは素晴らしいものですが、興味深いことに、比較するタイプの数、相対的な頻度、基礎となるデータのパターンなど、多くの異なる要因を考慮すると、異なる手法の相対コストは劇的に変化します。
正確な答えを得るには、自分のシステムでさまざまな方法でパフォーマンスを測定する必要があります。
If/Else チェーンは、少数の型比較のための効果的なアプローチであり、または、どの少数の型が表示されるものの大部分を構成することになるかを確実に予測できる場合です。 このアプローチの潜在的な問題は、型の数が増加すると、実行しなければならない比較の数も増加することです。
を実行した場合、次のようになります。
int value = 25124;
if(value == 0) ...
else if (value == 1) ...
else if (value == 2) ...
...
else if (value == 25124) ...
は、正しいブロックに入る前に、前の各if条件が評価されなければなりません。 一方
switch(value) {
case 0:...break;
case 1:...break;
case 2:...break;
...
case 25124:...break;
}
は、正しいコードのビットへの単純なジャンプを一つ実行します。
この例でより複雑になるのは、他のメソッドが整数値ではなく文字列のスイッチを使用している点で、これは少し複雑になっています。 低レベルでは、文字列は整数値と同じ方法で切り替えることができないので、C#コンパイラーはこれを動作させるためにいくつかのマジックを行います。
switchステートメントが十分に小さい場合(コンパイラが自動的に最適と考えることを行う場合)、文字列をオンにすると、if/elseチェーンと同じコードが生成されます。
switch(someString) {
case "Foo": DoFoo(); break;
case "Bar": DoBar(); break;
default: DoOther; break;
}
とは同じです。
if(someString == "Foo") {
DoFoo();
} else if(someString == "Bar") {
DoBar();
} else {
DoOther();
}
辞書内のアイテムのリストが十分に大きくなると、コンパイラは自動的に内部辞書を作成し、スイッチ内の文字列から整数のインデックスにマップし、そのインデックスに基づいてスイッチを作成します。
次のようになります (私がわざわざ入力するよりも多くのエントリを想像してみてください)。
静的フィールドは、型の switch 文を含むクラスに関連付けられた "hidden" 場所に定義されます。
Dictionary<string, int>
であり、揶揄されるような名前が付けられています。
//Make sure the dictionary is loaded
if(theDictionary == null) {
//This is simplified for clarity, the actual implementation is more complex
// in order to ensure thread safety
theDictionary = new Dictionary<string,int>();
theDictionary["Foo"] = 0;
theDictionary["Bar"] = 1;
}
int switchIndex;
if(theDictionary.TryGetValue(someString, out switchIndex)) {
switch(switchIndex) {
case 0: DoFoo(); break;
case 1: DoBar(); break;
}
} else {
DoOther();
}
いくつかの簡単なテストを実行したところ、If/Else メソッドは 3 つの異なる型 (型はランダムに分布) で switch よりも約 3 倍高速でした。 25 のタイプでは、スイッチはわずかなマージン (16%) で速く、50 のタイプではスイッチは 2 倍以上速くなります。
もし、大量のタイプでスイッチするのであれば、私は3番目の方法をお勧めします。
private delegate void NodeHandler(ChildNode node);
static Dictionary<RuntimeTypeHandle, NodeHandler> TypeHandleSwitcher = CreateSwitcher();
private static Dictionary<RuntimeTypeHandle, NodeHandler> CreateSwitcher()
{
var ret = new Dictionary<RuntimeTypeHandle, NodeHandler>();
ret[typeof(Bob).TypeHandle] = HandleBob;
ret[typeof(Jill).TypeHandle] = HandleJill;
ret[typeof(Marko).TypeHandle] = HandleMarko;
return ret;
}
void HandleChildNode(ChildNode node)
{
NodeHandler handler;
if (TaskHandleSwitcher.TryGetValue(Type.GetRuntimeType(node), out handler))
{
handler(node);
}
else
{
//Unexpected type...
}
}
これはTed Elliotが提案したものと似ていますが、完全な型オブジェクトの代わりにランタイムの型ハンドルを使うことで、リフレクションを通して型オブジェクトをロードするオーバーヘッドを回避しています。
以下は私のマシンでのいくつかの簡単なタイミングです。
5,000,000のデータ要素(mode=Random)と5つのタイプで3つの反復処理をテストしました。 方法 時間 最適の割合 If/Else 179.67 100.00 TypeHandleDictionary 321.33 178.85 TypeDictionary 377.67 210.20 スイッチ 492.67 274.21 5,000,000 個のデータ要素(mode=Random)と 10 種類のタイプで 3 回の繰り返しテスト 方法 時間 最適の割合 If/Else 271.33 100.00 271.33 100.00 TypeHandleDictionary 312.00 114.99 312.00 114.99 TypeDictionary 374.33 137.96 スイッチ 490.33 180.71 5,000,000 個のデータ要素(mode=Random)と 15 種類の型による 3 回の繰り返しテスト メソッド 時間 最適に対する割合 TypeHandleDictionary 312.00 100.00 312.00 100.00 If/Else 369.00 118.27 TypeDictionary 371.67 119.12 スイッチ 491.67 157.59 5,000,000 個のデータ要素(mode=Random)と 20 種類の型による 3 回の繰り返しテスト メソッド 時間 最適に対する割合 TypeHandleDictionary 335.33 100.00 TypeDictionary 373.00 111.23 If/Else 462.67 137.97 スイッチ 490.33 146.22 5,000,000 個のデータ要素(mode=Random)と 25 種類の型による 3 回の繰り返しテスト メソッド 時間 最適に対する割合 TypeHandleDictionary 319.33 100.00 319.33 100.00 TypeDictionary 371.00 116.18 スイッチ 483.00 151.25 483.00 151.25 Switch If/Else 562.00 175.99 5,000,000 個のデータ要素 (mode=Random) と 50 種類の型による 3 回の繰り返しテスト メソッド 時間 最適に対する割合 TypeHandleDictionary 319.67 100.00 319.67 100.00 TypeDictionary 376.67 117.83 スイッチ 453.33 141.81 If/Else 1,032.67 323.04
少なくとも私のマシンでは、型ハンドル辞書のアプローチは、メソッドの入力に使用される型の分布がランダムである場合、15以上の異なる型に対して他のすべてのアプローチに勝ります。 の分布がランダムである場合、15 種類以上の型に対して他のすべての方法を上回ります。
一方、入力が if/else チェーンで最初にチェックされる型のみで構成されている場合、そのメソッドは 多く より高速になります。
5,000,000個のデータ要素(mode=UniformFirst)と50種類の型による3回の繰り返しテスト 方法 時間 最適の割合 If/Else 39.00 100.00 TypeHandleDictionary 317.33 813.68 317.33 813.68 TypeDictionary 396.00 1,015.38 スイッチ 403.00 1,033.33
逆に、入力が常にif/elseチェーンの最後のものであれば、逆効果になります。
5,000,000個のデータ要素(mode=UniformLast)と50種類のタイプで3回の繰り返しテストを行った結果 方法 時間 最適の割合 TypeHandleDictionary 317.67 100.00 スイッチ 354.33 111.54 TypeDictionary 377.67 118.89 If/Else 1,907.67 600.52
入力についていくつかの仮定ができる場合、最も一般的ないくつかの型について if/else チェックを行い、それが失敗した場合に辞書駆動アプローチにフォールバックするハイブリッドなアプローチで最高のパフォーマンスを得られるかもしれません。
関連
-
[解決済み】C#でクエスチョンマークを2つ並べるとどんな意味になるのか?
-
[解決済み】C#におけるtypedefの等価性
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] callとapplyの違いは何ですか?
-
[解決済み] C#の正しいバージョン番号を教えてください。
-
[解決済み] C#のオートプロパティに初期値を与える最良の方法は何ですか?
-
[解決済み] DateTime型の誕生日から年齢を計算するにはどうしたらいいですか?
-
[解決済み] 型チェック:typeof、GetType、is?
-
[解決済み] 文字列フォーマット:% vs. .format vs. f-stringリテラル
-
[解決済み】大文字・小文字を区別しない「Contains(string)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】コンパイルエラー「未割り当てのローカル変数を使用しています」が発生したのはなぜですか?
-
[解決済み】「namespace x already contains a definition for x」エラーの修正方法は?VS2010にコンバートした後に発生しました。
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み】リソースの読み込みに失敗した:ステータス500(内部サーバーエラー)のサーバーの応答)
-
[解決済み】Unity 「関連するスクリプトを読み込むことができません」「Win32Exception: システムは指定されたファイルを見つけることができません"
-
[解決済み] スイッチオンタイプ」これ以上の代案はないのでしょうか?
-
[解決済み】C#でif/elseとswitch-caseを使うことに大きな違いはあるのでしょうか?
-
[解決済み】C#のスイッチオンタイプ【重複あり
-
[解決済み] このスイッチ/パターンマッチングの考え方にメリットはあるのでしょうか?
-
[解決済み] 型の大文字と小文字の切り替え c# [duplicate]