C# LINQ ToListのパフォーマンスについて

DEVELOP, Unity

※これはどこかで読んだ記事の内容を参考にしたものです。参照先を忘れてしまっていて、見つけ次第リンクを貼ります。

コードを書いていると、Listの操作をすることが多いかと思います。特に、Listの中の、ある要素を一括で取り出す時なんかSelect からのToListとかそこそこ、あると思います。

public static void TestFunc()
{
    var range = Enumerable.Range(1, 10000);
    var list = range.Where(_ => _ % 2 == 0)
                .Select(_ => (float)_)
                .ToList();
}

ここで何となくToListって遅くないの?って思ったので、mono C# のListの実装を読んでみます。
mono のToList
ほー、キャストやらなんやら詰まってますね。何よりListのnew の仕方が…。
なので、少し単純化します。

static class ListExtensions
{
    public static List<T> ToListEx<T>(this IEnumerable<T> source)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        var result = new List<T>();
        foreach (var t in source)
        {
            result.Add(t);
        }
        return result;
    }
}

IEnumerableを拡張して、ToListの代わりにToListExを用意しました。

public static void TestFunc()
{
    var range1 = Enumerable.Range(1, 10000);
    var range2 = Enumerable.Range(1, 10000);
    var start = DateTime.Now;
    var list1 = range1.Where(_ => _ % 2 == 0)
                .Select(_ => (float)_)
                .ToList();
    Debug.Log((double)(DateTime.Now.Ticks - start.Ticks) / TimeSpan.TicksPerMillisecond + "ms List");
    start = DateTime.Now;
    var list2 = range2.Where(_ => _ % 2 == 0)
                 .Select(_ => (float)_)
                 .ToListEx();
    Debug.Log((double)(DateTime.Now.Ticks - start.Ticks) / TimeSpan.TicksPerMillisecond + "ms ListEx");
}

計測結果

関数時間(ms)
ToList2.0469
ToListEx1.0025

倍程度高速化できました。Releaseビルドなど、最適化具合でどれほど意味があるのかは別として、Listとかよく使うクラスは自作してしまいたい気持ちに駆られます。

Posted by kazupon