HEXA BLOG

プログラム

HEXA BLOGプログラム2019.7.24

[c#]EnumのGetHashCodeは遅いの?

お久しぶりです。大阪プログラマーの澤野です。

最近EnumのGetHashCodeの実装を知る機会があり、もしかしてEnumのGetHashCodeは遅いの?と疑問に思ってしまったので
Int32.GetHashCodeとの処理負荷の比較をゆるーく行いました。
間違っているかもしれないので参考程度に見てくれればと思います。

早速ですがInt32とEnumのGetHashCodeの実装は以下の通りです。

Int32.GetHashCodeの実装
値をそのまま返すだけです。
ReferenceSource

Enum.GetHashCodeの実装
型でswitchしてからキャストして返しています。
ReferenceSource

非常に簡易にですが以下のコードで処理負荷の比較を行ってみようかと思います。

環境
ターゲットフレームワーク:.Net Core2.1
プロセッサ:Intel(R) Core(TM) i7-6700 CPU @3.40GHz

参考コード

enum TestEnum : int {
Test0 = 1,
}
static void Main(string[] args)
{
// 500万回GetHashCodeを呼ぶ
const int MaxCount = 5000000;
// EnumTest
{
var sum = 0;
var sw = new System.Diagnostics.Stopwatch();
for (var index = 0; index < MaxCount; ++index)
{
sw.Start();
sum += TestEnum.Test0.GetHashCode();
sw.Stop();
}
System.Diagnostics.Trace.WriteLine($"EnumTest = {sw.ElapsedMilliseconds}ミリ秒, Sum = {sum}");
}
// IntTest
{
var sum = 0;
int value0 = 1;
var sw = new System.Diagnostics.Stopwatch();
for (var index = 0; index < MaxCount; ++index)
{
sw.Start();
sum += value0.GetHashCode();
sw.Stop();
}
System.Diagnostics.Trace.WriteLine($"IntTest = {sw.ElapsedMilliseconds}ミリ秒, Sum = {sum}");
}
}

ちなみにILSpyで参考コードのILを見るとInt32のGetHashCodeは以下のようにcallで呼ばれているのに対し
EnumのGetHashCodeはcontrainedを行ってからcallvirtで呼んでいます。
これはInt32より遅くなる気がしますね!
IntTestのIL
// num2 += num3.GetHashCode();
IL_006f: ldloc.s 4
IL_0071: ldloca.s 5
IL_0073: call instance int32 [System.Runtime]System.Int32::GetHashCode()

EnumTestのIL
// num += TestEnum.Test0.GetHashCode();
IL_0012: ldloc.0
IL_0013: ldc.i4.1
IL_0014: stloc.3
// (no C# code)
IL_0015: ldloca.s 3
IL_0017: constrained. ConsoleApp1.Program/TestEnum
IL_001d: callvirt instance int32 [System.Runtime]System.Object::GetHashCode()

それでは処理負荷の計測結果です。
計測結果
Debugビルド
EnumTest = 438ミリ秒, Sum = 5000000
IntTest = 371ミリ秒, Sum = 5000000

Releaseビルド
EnumTest = 363ミリ秒, Sum = 5000000
IntTest = 330ミリ秒, Sum = 5000000

処理負荷の計測方法が間違っている気がしなくもないですが上記のコードで計測する限り
GetHashCodeを500万回呼ぶとEnum.GetHashCodeの方がReleaseビルドで30msほど遅くなっていることが分かります。
しかし、500万回も呼ぶことはそうそうないので処理負荷はほとんど誤差といっても良いのではないでしょうか。
何とも面白くない結果になってしまいましたがEnumのGetHashCodeは使用を懸念するほど遅くはなさそうです。

次回はc#のOpCode周りのネタを考えてきます。

RECRUIT

大阪・東京共にスタッフを募集しています。
特にキャリア採用のプログラマー・アーティストに興味がある方は下のボタンをクリックしてください

RECRUIT SITE 

S