C#+WPFチューニング戦記

C#とWPFで高速なコードと最適なシステムを書くためにやってきたいろいろな事を書いてみます。.NET Frameworkのソースコードを読み解きましょう。なお、ここに書かれているのは個人の見解であって何らかの団体や企業の見解を代表するものではありません。

enumはenum以外の用途で使うと遅いのは何故か

enumは糖衣構文です。実態はclass Enumです。

このEnumenumの本分を尽くす限りにおいては高速です。

しかし、C/C++におけるenumとは根本的に異なっており、int等へのキャストは高速なのに、GetHashCode等のクリティカルなシーンにおいて非常に低速な実装を伴っています。具体的にどういうことかというと

Dictionary<TKey,TValue> のTKeyにenumを使うと低速で、TKeyをintにしておいてintにキャストしたenumを使うと高速ということです。

ええ、馬鹿な!と思います。しかし、速度には1桁程度の差が出ます。

アルゴリズム的に線形探索などを繰り返すコードは必要時以外は論外としまして、型によって何故だか速い辞書、遅いHashSetが生まれる理由があります。

遅いといわれるものの多くはGetHashCodeの速度の問題で、最近調べた事例では順位は以下の通り。

  1. GetHashCodeについては、32bit以下の値型が最速。
  2. 次いでGuidやTypeなどの値型で品質の良いGetHashCodeを実装するもの(GuidとTypeこの二つは厳密に測定してもほぼ等速です。決して遅くはありません。最適化時でintの4倍程度のコストです)。
  3. 具体的なGetHashCodeの実装があるクラス(遅い理由はILに展開されたところで callvirt になってしまうからです。惜しいですが。)
  4. 具体的なGetHashCodeの実装が無いクラス
  5. そして以下の実装を持つEnumのGetHashCodeは極め付けで低速です。
    http://referencesource.microsoft.com/#mscorlib/system/enum.cs#836

それにしても、この実装はどうにかならなかったのでしょうか。何か古いコードが邪魔をしてここで破壊的な変更を行うことができなかったか、糖衣構文の仕様変更を嫌ったか。あと、具体的にintへのキャストで十分な速度を得られるというところも理由かもしれません。

Enumジェネリックにするクラスデザインとか、個人的には賛成です。誰かこれをC#の糖衣構文化してくれないでしょうか。

もともとC/C++に馴染んだ者として、遅いenumは辛いですからね。

そういえば、enumは列挙も相当遅いので、コードとしては綺麗ではありませんが速度が必要な時はint等からenumへのキャストをしてください。