R.Tanaka.Ichiro's Blog

主にC# な話題です

目次

Blog 利用状況

ニュース

switch case が最適なのか?

僕の尊敬するJねっとさんが、switch case の最適化に関する話をしていたログをネット上で見かけました。
どのように最適化されるのかはわかりませんが、使用方法としての最適さは検証してみればわかるだろう・・・と言うことで早速試してみました。

用意したのは、以下のようなコードです。
(System, System.Collections, System.Diagnostics が using  されています)


static void Main() {
  string target = "j"; // ここを書き換える

  Debug.WriteLine("------------------------------");
  Debug.WriteLine("target:" + target);

  Stopwatch stopWatch = new Stopwatch();
  int count = 10000000;

  //=====================================
  stopWatch.Start();
  for (int i = 0; i < count; ++i) {
    string s = testIf(target);
  }
  stopWatch.Stop();
  結果出力(stopWatch, "IF を使った場合");

  //=====================================
  stopWatch.Reset();
  stopWatch.Start();
  for (int i = 0; i < count; ++i) {
    string s = testSwitch(target);
  }
  stopWatch.Stop();
  結果出力(stopWatch, "Switch を使った場合");

  //=====================================
  Hashtable h = InitializeHashtable();
  stopWatch.Reset();
  stopWatch.Start();
  for (int i = 0; i < count; ++i) {
    string s = h[target].ToString();
  }
  stopWatch.Stop();
  結果出力(stopWatch, "Hashtable を使った場合");

  Debug.WriteLine("------------------------------");
}

static private Hashtable InitializeHashtable() {
  Hashtable h = new Hashtable();
  h.Add("a", "あ");
  h.Add("b", "い");
  h.Add("c", "う");
  h.Add("d", "え");
  h.Add("e", "お");
  h.Add("f", "か");
  h.Add("g", "き");
  h.Add("h", "く");
  h.Add("i", "け");
  h.Add("j", "こ");
  return h;
}

static string testSwitch(string i) {
  switch (i) {
    case "a": return "あ";
    case "b": return "い";
    case "c": return "う";
    case "d": return "え";
    case "e": return "お";
    case "f": return "か";
    case "g": return "き";
    case "h": return "く";
    case "i": return "け";
    case "j": return "こ";
    default: return "さ";
  }
}
static string testIf(string i) {
  if (i == "a") return "あ";
  if (i == "b") return "い";
  if (i == "c") return "う";
  if (i == "d") return "え";
  if (i == "e") return "お";
  if (i == "f") return "か";
  if (i == "g") return "き";
  if (i == "h") return "く";
  if (i == "i") return "け";
  if (i == "j") return "こ";
  return "さ";
}

static private void 結果出力(Stopwatch stopWatch, string message){
  string s = message + ":" + stopWatch.ElapsedMilliseconds.ToString();
  Debug.WriteLine(s.PadLeft(25));
}


結果は、次のようになりました。

------------------------------
target:a
            IF を使った場合:316
       Switch を使った場合:1281
    Hashtable を使った場合:1787
------------------------------
target:j
           IF を使った場合:2526
       Switch を使った場合:1259
    Hashtable を使った場合:1783
------------------------------

一番最初に見つかるであろう a をターゲットにした時「IF を使った場合」が素晴らしく早いことがわかります。

しかし、一番最後の j をターゲットにすると、一番遅くなってしまったのでした。選択肢が 10 しかないにも関わらず、です。

・・・ダメダメじゃんw

一方、Switch , Hashtable を使った場合は、共に安定した結果になりました。

つまり、Switch では、case を列挙した際の順序の差が出ないことがわかります。
ちなみに、実験では a をターゲットにした場合よりも j をターゲットにした場合の方が早くなっていますが、これは何度か実行すると数値が当然動きます。
つまりは誤差の範囲と考えてよいでしょう。

Hashtable も Switch Case と同様に登録順に関係ありません。
これは恐らく、Hash 値によって格納場所を対応付けしているから、探すという処理が不要になるためかと思われます。

Switch の方が幾分早いので、今回のような処理なら Swicth を使うのが最適な選択と言えそうです。
ただ、この件数が増えた場合は、Switch と Hashtable を使った結果が

変わるかも

しれません。(真意の程を誰か教えて下さい)

投稿日時 : 2007年1月31日 11:24

Feedback

# re: switch case が最適なのか? 2007/01/31 11:35 シャノン

if は線形探索なのでO(n)、Hashtable は O(1) というやつですね。
switch は、いわゆる「ジャンプテーブル」という方式で実装していると思われます(switch ジャンプテーブル でぐぐるといろいろ出てきます)ので、件数が増えるとむしろ効果を発揮するでしょう。
ただし、これはコンパイラの実装依存であり最適化の範疇なので、変わる可能性はありますね。
「オブジェクト指向ではあまりswitchを使うな」とも言いますし…

# re: switch case が最適なのか? 2007/01/31 11:55 じゃんぬねっと

MSIL を覗けばわかるでしょう。
最適化というレベルから飛び出たことをしていますよ。

# re: switch case が最適なのか? 2007/01/31 11:56 じゃんぬねっと

> Jねっと

会社名は出さないでくださいw

# re: switch case が最適なのか? 2007/01/31 11:58 黒龍

Switch~Caseはジャンプテーブル実装になっているものが多いですね。Ifも最適化で可能なんですが意図的にテーブル化されていないとかいう話を聞いたことがあります。
投入される値にばらつきがある場合(たとえば99%特定の値が来る)にIfの並び順によって最適化することが可能だからとかいう理屈です。
こういった部分はコンパイラ任せにできないところなので手動での最適化の余地があるというのは望ましいと思います。

# re: switch case が最適なのか? 2007/01/31 12:39 囚人

ジャンプテーブルという言葉ははじめて聞きましたが、C 書いたプログラムをで逆アセンブルすると面白い事をしているのが読めます。

>投入される値にばらつきがある場合(たとえば99%特定の値が来る)にIfの並び順によって最適化することが可能だからとかいう理屈です。

組み込み屋の中には if で判定する並びをやたらと気にする人がいますね。最近はそういった事を気にしたコードを見ないから寂しいもんです。

# re: switch case が最適なのか? 2007/01/31 12:40 シャノン

> MSIL を覗けばわかるでしょう。
> 最適化というレベルから飛び出たことをしていますよ。

意図的に覗きません。
どういう実装をしているか知りませんが、言語仕様に実装方法が規定されているならまだしも(それはそれでILを見る必要はない)、そうでないなら、どうであろうが実装詳細であり、変わる可能性はあるからです。

# re: switch case が最適なのか? 2007/01/31 14:34 えムナウ

>switch case の最適化
>「オブジェクト指向ではあまりswitchを使うな」
Strategy (ストラテジー) パターンとState (ステート) パターンですね。

なおこ(・∀・)さんとこ。
http://naoko.wankuma.com/designpatterns/designpatterns_0010_strategy.html
http://naoko.wankuma.com/designpatterns/designpatterns_0019_state.html

中西さんとこ。
http://hccweb1.bai.ne.jp/tsune-1/CSharp/strategy.html
http://hccweb1.bai.ne.jp/tsune-1/CSharp/state.html

# re: switch case が最適なのか? 2007/01/31 15:20 かずくん

>>「オブジェクト指向ではあまりswitchを使うな」
>Strategy (ストラテジー) パターンとState (ステート) パターンですね。

かといって、現実問題として、細かすぎる粒度でStrategyとか使用すると、コードが追いにくくなる罠

ここら辺のバランス感覚は難しいところ。
#こんな事言うと、純粋なOO信者に、「何をバカなことを」って言われちゃうんだろうな...

# re: switch case が最適なのか? 2007/01/31 16:08 ぽぴ王子

僕の尊敬する囚人さんが、ジャンプテーブルという言葉を初めて聞いたという事実に衝撃を受けている私ですが(笑)ジャンプテーブルって今じゃあんまり一般的じゃないのかな?それともたまたま?
アセンブラというかアセンブリ言語?を経験している人なら過去に通った道っぽいですが…いやまあ、知らなくてもなんとかなる技術ではありますけど。

> 会社名は出さないでくださいw
よくこのブログで話題に上るJったさんとかS人さんなんてのも会社名ですか?w
# P王子とか。

> MSIL を覗けばわかるでしょう。
> 最適化というレベルから飛び出たことをしていますよ。

これって、本当に最適化されているのか(速いコードが出力されているか)はMSILを覗けばわかる、逆に言えばMSILこそが真実だ、という話ですよね?
# 真実はいつもひとつ!名探偵コナン!
# 頭脳は子供、体は大人、名探偵小枝!(違
# ↑桂小枝の持ちネタなんだけど、嫁が大好きなの

# re: switch case が最適なのか? 2007/01/31 21:57 ひろえむ

StrategyとかStateをselect case/switch caseと直結するのはちょっとアレですが(^^;

OOだってなんでもかんでもswitchがだめで、デザパタというワケではないと思いますよ(^^;

Strategyはロジックを入れ替えするときに便利なパターンだし、Stateは状態によって振る舞いが変わるときに使うパターン。

それぞれ目的がちゃんとあるワケで、これとswitchを同列に見るのはちょっと乱暴な気がします(^^;;;

なので、OOだってなんでもかんでもswitch使うなってことじゃなくて、適材適所に使える場所であれば使ってもいいんじゃないかなと思うんですがどうでしょ?(^^;

# re: switch case が最適なのか? 2007/01/31 23:48 シャノン

ま、「同じswitch-caseが2回以上あったらOO的手法で置き換えを検討せよ」とは言われますね。

# re: switch case が最適なのか? 2007/02/01 0:06 中博俊

てかね、
enumなんてswitchするためにあるわけでね。
もんもん。

# re: switch case が最適なのか? 2007/02/01 0:56 ひろえむ

>ま、「同じswitch-caseが2回以上あったらOO的手法で置き換えを検討せよ」とは言われますね。

それはswitch-caseに限ったことではなくて、同じロジックでもそうですね(^^;

# re: switch case が最適なのか? 2007/02/01 2:21 RUN

testIfはあからさまに処理ステップ数が多いじゃないか。
実行する以前に後半が遅いのが見て取れる。
せめてelseifでつなぐとかしてもうちょい小細工があっても(いや、まぁだからと言ってIFがswitchより早くなると言う物ではないが、コンパイラによる最適化のされやすさとかごにょごにょ)

# re: switch case が最適なのか? 2007/02/01 13:44 R・田中一郎

シャノン さん

>switch は、いわゆる「ジャンプテーブル」という方式で実装していると思われます(switch ジャンプテーブル でぐぐるといろいろ出てきます)

面白そうですね。
じっくり調べてみようと思います。

------------------------------
じゃんぬねっと さん

>最適化というレベルから飛び出たことをしていますよ。

そうか・・・MSILを覗いてみれば良かったんですね。
ありがとうございます。

>> Jねっと
>
>会社名は出さないでくださいw

騙されないぞっw

------------------------------
黒龍 さん

>Ifも最適化で可能なんですが意図的にテーブル化されていないとかいう話を聞いたことがあります。

なるほど。
いろいろ深く考えられているんですねぇ。

------------------------------
囚人 さん

>C 書いたプログラムをで逆アセンブルすると面白い事をしているのが読めます。

逆汗っすか。やったこと無かったですね。
これも、今度試してみたいと思います。

>み込み屋の中には if で判定する並びをやたらと気にする人がいますね。最近はそういった事を

9割が先頭でマッチするなら、この方法が爆速ですもんね。

------------------------------
えムナウ さん

>trategy (ストラテジー) パターンとState (ステート) パターンですね。

初めて聞いた言葉でした。
勉強させていただきます _(_*_)_

------------------------------
かずくん さん

>ここら辺のバランス感覚は難しいところ。

実は、僕も同感だったりします^^;

------------------------------
ぽぴ王子 さん

>僕の尊敬する囚人さんが

S人さんですねw

------------------------------
ひろえむ さん

>OOだってなんでもかんでもswitchがだめで、デザパタというワケではないと思いますよ(^^;

そうですよね。同感です。

>なので、OOだってなんでもかんでもswitch使うなってことじゃなくて、適材適所に使える場所であれば使ってもいいんじゃないかなと思うんですがどうでしょ?(^^;

いま、ひろえむさんがいいこと言った。

------------------------------
中博俊 さん

>enumなんてswitchするためにあるわけでね。

そうだったのですね。
もんもん。

------------------------------
RUN さん

>testIfはあからさまに処理ステップ数が多いじゃないか。

ぎくっ。

>実行する以前に後半が遅いのが見て取れる。

ぎくぎくっ。

>せめてelseifでつなぐとかしてもうちょい小細工があっても(いや、まぁだからと言ってIFがswitchより早くなると言う物ではないが、コンパイラによる最適化のされやすさとかごにょごにょ)

ぎくぎくぎくっ。

・・・・宿題ということにw

# re: switch case が最適なのか? 2007/02/01 14:33 刈歩 菜良

ジャンプテーブルわたしも知りませんでした。
# アセンブリは情報処理の勉強でCASLをちょいと勉強したことしかないので...
# そもそもおおむかしBASICを勉強してて、Peek、Pookがわけわかめで挫折した。

VBだとCaseに不等号での比較とか、範囲指定とか書けちゃうから、ジャンプテーブルは使えず、ifと同じになっちゃうのかな?もしかして?

# re: switch case が最適なのか? 2007/02/01 20:21 R・田中一郎

刈歩 菜良 さん

># そもそもおおむかしBASICを勉強してて、Peek、Pookがわけわかめで挫折した。

Peek, Pook は、メモリの番地に値を設定したり、取得したりする命令でしたっけね。

>VBだとCaseに不等号での比較とか、範囲指定とか書けちゃうから、ジャンプテーブルは使えず、ifと同じになっちゃうのかな?もしかして?

あ、これは僕も気になっていたところでした。
早速 MSIL を覗いてみなければ・・・

# re: switch case が最適なのか? 2007/02/06 9:09 じゃんぬねっと

> 意図的に覗きません。
> どういう実装をしているか知りませんが、言語仕様に実装方法が規定されているならまだしも
> (それはそれでILを見る必要はない)、そうでないなら、どうであろうが実装詳細であり、
> 変わる可能性はあるからです。

ん? なにやら会話の流れを誤解しているようですね。
もうフォローされているので、良いですけどw

# re: switch case が最適なのか? 2007/09/19 9:13 Simos

Nice

# jEXneUlXIqU 2011/12/13 20:23 http://www.d4women.net/yasmin.php

Of course, I understand a little about this post but will try cope with it!!...

タイトル
名前
Url
コメント