読者です 読者をやめる 読者になる 読者になる

【C#】Enumの爆速ForEach

Enumをforeachで回すと遅いよと聞いて
自前で書いてみたら爆速ForEachができた

// 以下のenum定義を使用する
enum Days {Sat=10, Sun=20, Mon, Tue, Wed, Thu, Fri};

まず結果(1,000,000回を回す)

// 1回目
foreach : 1328ms
EnumExtension.ForEach : 1283ms
EnumExtension.ForEachList : 482ms
EnumForEach<T>.Exec : 56ms

// 2回目
foreach : 1370ms
EnumExtension.ForEach : 1357ms
EnumExtension.ForEachList : 635ms
EnumForEach<T>.Exec : 61ms

// 3回目
foreach : 1342ms
EnumExtension.ForEach : 1360ms
EnumExtension.ForEachList : 488ms
EnumForEach<T>.Exec : 62ms

実装詳細

foreach

普通のforeach

foreach(Days days in Enum.GetValues(typeof(Days))) {
}

EnumExtension.ForEach

Enum(自前)拡張メソッド

public static class EnumExtension
{
    public static void ForEach<T>(Action<T> action) where T : struct, IConvertible
    {
        var type = typeof(T);
        foreach(T v in Enum.GetValues(type))
        {
            action((T)v);
        }
    }
}
// 使い方
EnumExtension.ForEach<Days>( days => {} );

速度がほぼforeachと変わらない

EnumExtension.ForEachList

Enum(自前)拡張メソッド:Listキャスト版

public static class EnumExtension
{
    public static void ForEachList<T>(Action<T> action) where T : struct, IConvertible
    {
        var type = typeof(T);
        var values = Enum.GetValues(type).Cast<T>().ToList();
        var count = values.Count;
        for(int i = 0 ; i < count ; ++i) {
            action((T)values[i]);
        }
    }
}
// 使い方
EnumExtension.ForEachList<Days>( days => {} );

Enum.GetValues(...)してListにキャストする方が遅いと思いきや
まさかかかった時間は半分以下に、ランダムアクセス早い!

EnumForEach.Exec

ジェネリッククラス版:static変数を持ち、反則のチートしてる

public class EnumForEach<T> where T : struct, IConvertible
{
    static List<T> Values = Enum.GetValues(typeof(T)).Cast<T>().ToList();
    static int Count = Values.Count;
        
    public static void Exec(Action<T> action)
    {
        for(int i = 0 ; i < Count ; ++i) {
            action((T)Values[i]);
        }
    }
}
// 使い方
EnumForEach<Days>.Exec( days => {} );

爆速!かかった時間はforeachの20分の1以下

最後に

  • 測定方法が間違ってないかしら?怖いorz
  • 疑念点
    • foreachみたいにループ中のbreak脱出はできない
    • メモリ消費を考えてない(それほど心配ではないが)
  • 俺は普通のforeachを使う(常識を考え百万回を回さないよね)

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ