替え玉バリカタでお願いします

お仕事と、お仕事そうでお仕事じゃない、少しお仕事な備忘など。

forとSumの実行速度が違いすぎて吐きそう

はじめに

もしこのエントリに辿り着いた方がいたら、
新たに「forとforeachとSumにおける実行速度の違い」というエントリを書いたので、
ここは見ちゃダメ!


なんですが、自戒を込めて残しておく。。

以下は黒歴史w

気分転換に、1〜nまでの総和を求める的なコードをfor版とLinq.Sum()版で書いてみた。
そしたらコードの実行速度が違いすぎて吐きそうになった。

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace StaticMethodSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var instance = new StaticMethodSample();
            var instanceWithLinq = new StaticMethodSampleWithLinq();

            // data
            var list = new List<decimal>();
            for (int i = 0; i < 500000; i++)
            {
                list.Add(i);
            }

            // non-Linq
            {
                // instance method
                var sw = new Stopwatch();
                {
                    sw.Start();
                    instance.getSumInstance(list);
                    sw.Stop();
                    System.Console.WriteLine("instance method:{0} msec", sw.ElapsedMilliseconds);
                }

                // static mehtod
                {
                    sw.Start();
                    StaticMethodSample.getSumStatic(list);
                    sw.Stop();
                    System.Console.WriteLine("static mehtod:{0} msec", sw.ElapsedMilliseconds);
                }
            }

            // with-Linq
            {
                // instance method
                var sw = new Stopwatch();
                {
                    sw.Start();
                    instanceWithLinq.getSumInstance(list);
                    sw.Stop();
                    System.Console.WriteLine("instance method:{0} msec", sw.ElapsedMilliseconds);
                }

                // static mehtod
                {
                    sw.Start();
                    StaticMethodSampleWithLinq.getSumStatic(list);
                    sw.Stop();
                    System.Console.WriteLine("static mehtod:{0} msec", sw.ElapsedMilliseconds);
                }
            }

        }
    }

    class StaticMethodSample
    {
        public decimal getSumInstance(List<decimal> list)
        {
            var sum = 0;
            for (int i = 0; i < list.Count; i++)
            {
                sum += i;
            }
            return sum;
        }

        public static decimal getSumStatic(List<decimal> list)
        {
            var sum = 0;
            for (int i = 0; i < list.Count; i++)
            {
                sum += i;
            }
            return sum;
        }
    }

    class StaticMethodSampleWithLinq
    {
        public decimal getSumInstance(List<decimal> list)
        {
            return list.Sum();
        }

        public static decimal getSumStatic(List<decimal> list)
        {
            return list.Sum();
        }
    }
}

実行結果:
instance mehtod:1 msec
static method:3 msec
instance mehtod:20 msec
static method:40 msec

しかもstaticにしたほうが遅い。staticにすると早くなるんじゃなかったけ?と。インスタンスメソッドとスタティックの違いはまとめておきたい。ILも読んだ方が良いかな。
でもSum()ってやると可読性が抜群に良いですな。バグも出ない。あと、このコードだと単純過ぎるので可読性の比較対象にならないけど、実際はSum()を使ってくれた方が人間には優しい。


Linq.Sum()の中身ってどうなってるの?

ちなみにSum()の中身を見てみると、foreachを使ってる。だから遅い?中でnewしてるし。
foreachとforに関しては、実は大して差が無いという話なので、気にする点では無いかも。

namespace System.Linq
{
  [__DynamicallyInvokable]
  public static class Enumerable
  {
    [__DynamicallyInvokable]
    public static Decimal Sum(this IEnumerable<Decimal> source)
    {
      if (source == null)
        throw Error.ArgumentNull("source");
      Decimal num1 = new Decimal(0);
      foreach (Decimal num2 in source)
        num1 += num2;
      return num1;
  }
}

何にせよもう少し調べるなりして、まとめたい。

広告を非表示にする