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

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

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

forとforeachとSumにおける実行速度の違い

C# Linq

初めは「forとSumの実行速度が違いすぎて吐きそう」というエントリを書いたものの、
計測が誤っていたり計測対象の処理が全然違ったり、ひどい間違いを犯してしまったので、もう一度やってみた。
id:neueccさんご指摘ありがとうございます!

やりたかったこと

  • for/foreach/Sumで実行速度を比較したい
  • 計算対象のデータを変えて、変化をざっくり見たい
  • 金を計算するケースが多いので、decimalを使いたい

ソース

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

namespace ConsoleApplication13
{
    class Program
    {
        static void Main(string[] args)
        {
            var datas = new ArrayList {100, 10000, 100000, 1000000, 5000000};

            for (int i = 0; i < datas.Count; i++)
            {
                // data
                var cnt = (int)datas[i];
                var list = new List<decimal>();
                for (int j = 0; j < cnt; j++)
                {
                    list.Add(j);
                }

                Console.WriteLine("========== count={0:##,###}", cnt);

                var sw = new Stopwatch();

                // non-Linq
                sw.Start();
                var result_foreach = Sum_A(list);
                sw.Stop();
                Console.WriteLine("result_foreach={0} : {1} msec", result_foreach, sw.ElapsedMilliseconds);

                sw.Restart();
                var result_for = Sum_B(list);
                sw.Stop();
                Console.WriteLine("result_for={0} : {1} msec", result_for, sw.ElapsedMilliseconds);

                // Linq
                sw.Restart();
                var result_Linq = Sum_Linq(list);
                sw.Stop();
                Console.WriteLine("result_Linq={0} : {1} msec", result_Linq, sw.ElapsedMilliseconds);
            }
        }

        public static decimal Sum_A(List<decimal> list)
        {
            var sum = 0m;
            foreach (var x in list)
            {
                sum += x;
            }
            return sum;
        }

        public static decimal Sum_B(List<decimal> list)
        {
            var cnt = list.Count;
            var sum = 0m;
            for (int i = 0; i < cnt; i++)
            {
                sum += list[i];
            }
            return sum;
        }

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

実行結果


========== count=100
result_foreach=4950 : 0 msec
result_for=4950 : 0 msec
result_Linq=4950 : 1 msec
========== count=10,000
result_foreach=49995000 : 0 msec
result_for=49995000 : 0 msec
result_Linq=49995000 : 0 msec
========== count=100,000
result_foreach=4999950000 : 3 msec
result_for=4999950000 : 3 msec
result_Linq=4999950000 : 3 msec
========== count=1,000,000
result_foreach=499999500000 : 32 msec
result_for=499999500000 : 30 msec
result_Linq=499999500000 : 34 msec
========== count=5,000,000
result_foreach=12499997500000 : 160 msec
result_for=12499997500000 : 150 msec
result_Linq=12499997500000 : 172 msec

分かったこと

  • 計算時間は for < foreach < Sumとなっており、リストに一発でアクセスするlist[n]がやっぱり速い
  • 対象が10万件ぐらいまでは差がない
  • 対象が100万件のケースでは差があるが4msec程度の差でしか無い

結論

  • 多量データを想定していても、ぶっちゃけSumで基本OK
  • 気にしたい処理であっても、おおよそ10msec単位程度の誤差を許すのであればSumでOK
  • msec単位で削りたい場合は、多量データを想定する処理はforで書きたい
広告を非表示にする