前回、C#におけるループステートメントの速度検証をまとめてみました。検証方法が未熟な箇所が多々あったため、今回は@Midoliyさんにご紹介いただきましたBenchmarkDotNet
を用いて検証を実施します。
実施すること
- 1億個の要素を持った配列およびリストを用意する。
- 準備した配列、リストに対して検証する。
- 単純にぐるぐる回す。
- ぐるぐる回しながら2の倍数を足し込んでいく。
対象のループステートメント
- for
- foreach
- do
- do-while
- LINQ(Query形式):足し込み検証のみ実施
- LINQ(Method形式):足し込み検証のみ実施
結果
単純にぐるぐる回す(配列)
Method | Mean | Error | StdDev | Median |
---|
BenchFor_Array | 29.08 ms | 0.1590 ms | 0.1410 ms | 29.05 ms |
BenchForEach_Array | 48.22 ms | 0.0428 ms | 0.0334 ms | 48.22 ms |
BenchDo_Array | 28.93 ms | 0.0829 ms | 0.0735 ms | 28.93 ms |
BenchDoWhile_Array | 36.09 ms | 2.6406 ms | 7.7859 ms | 33.17 ms |
単純にぐるぐる回す(リスト)
Method | Mean | Error | StdDev | Median |
---|
BenchFor_List | 36.53 ms | 0.4746 ms | 0.4439 ms | 36.40 ms |
BenchForEach_List | 248.81 ms | 10.3583 ms | 12.3308 ms | 244.77 ms |
BenchDo_List | 36.49 ms | 0.4889 ms | 0.4573 ms | 36.30 ms |
BenchDoWhile_List | 36.19 ms | 0.1416 ms | 0.1182 ms | 36.19 ms |
※配列とリストでforeachの速度がなぜここまで変わるのかは、@Tokeiyaさんの配列に対するforとforeachが非常にわかりやすかったです。
2の倍数の足し込み(配列)
Method | Mean | Error | StdDev | Median |
---|
BenchForWithCalc_Array | 151.77 ms | 0.3014 ms | 0.2819 ms | 151.79 ms |
BenchForEachWithCalc_Array | 136.51 ms | 0.1996 ms | 0.1867 ms | 136.46 ms |
BenchDoWithCalc_Array | 151.72 ms | 0.2464 ms | 0.2305 ms | 151.65 ms |
BenchDoWhileWithCalc_Array | 151.03 ms | 1.1535 ms | 1.0225 ms | 150.97 ms |
BenchLINQQuery_Array | 611.51 ms | 5.0230 ms | 4.6985 ms | 613.74 ms |
BenchLINQMethod_Array | 589.09 ms | 11.6493 ms | 11.4412 ms | 586.88 ms |
2の倍数の足し込み(リスト)
Method | Mean | Error | StdDev | Median |
---|
BenchForWithCalc_List | 169.25 ms | 0.3809 ms | 0.3563 ms | 169.37 ms |
BenchForEachWithCalc_List | 299.09 ms | 3.3102 ms | 3.0963 ms | 300.62 ms |
BenchDoWithCalc_List | 172.82 ms | 2.8077 ms | 2.1921 ms | 173.18 ms |
BenchDoWhileWithCalc_List | 169.38 ms | 0.5669 ms | 0.4734 ms | 169.22 ms |
BenchLINQQuery_List | 814.73 ms | 5.5605 ms | 5.2013 ms | 816.72 ms |
BenchLINQMethod_List | 825.85 ms | 7.5451 ms | 6.6885 ms | 825.91 ms |
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
Median : Value separating the higher half of all measurements (50th percentile)
検証ソース
usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem.Collections.Generic;usingSystem.Linq;namespaceBenchmarks{publicclassLoopBenchmarkTest{privatestaticreadonlyintlistCnt=100_000_000;// 要素数privatestaticreadonlyint[]numArray;// 検証配列privatestaticreadonlyList<int>numList;// 検証リストstaticLoopBenchmarkTest(){numArray=Enumerable.Range(0,listCnt).ToArray();numList=newList<int>(numArray);}#region Array
[Benchmark]publiclongBenchFor_Array(){for(vari=0;i<=numArray.Length-1;i++){}return0;}[Benchmark]publiclongBenchForEach_Array(){foreach(varnuminnumArray){}return0;}[Benchmark]publiclongBenchDo_Array(){vari=0;while(i<=numArray.Length-1){i++;}return0;}[Benchmark]publiclongBenchDoWhile_Array(){vari=0;do{i++;}while(i<=numArray.Length-1);return0;}#endregion#region List
[Benchmark]publiclongBenchFor_List(){for(vari=0;i<=numList.Count-1;i++){}return0;}[Benchmark]publiclongBenchForEach_List(){foreach(varnuminnumList){}return0;}[Benchmark]publiclongBenchDo_List(){vari=0;while(i<=numList.Count-1){i++;}return0;}[Benchmark]publiclongBenchDoWhile_List(){vari=0;do{i++;}while(i<=numList.Count-1);return0;}#endregion
#region ArrayWithCalc
[Benchmark]publiclongBenchForWithCalc_Array(){vartotal=0;for(vari=0;i<=numArray.Length-1;i++){if(i%2==0)total+=numArray[i];}returntotal;}[Benchmark]publiclongBenchForEachWithCalc_Array(){vartotal=0;foreach(varnuminnumArray){if(num%2==0)total+=num;}returntotal;}[Benchmark]publiclongBenchDoWithCalc_Array(){vari=0;vartotal=0;while(i<=numArray.Length-1){if(i%2==0)total+=numArray[i];i++;}returntotal;}[Benchmark]publiclongBenchDoWhileWithCalc_Array(){vari=0;vartotal=0;do{if(i%2==0)total+=numArray[i];i++;}while(i<=numArray.Length-1);returntotal;}[Benchmark]publiclongBenchLINQQuery_Array(){vartotal=(fromxinnumArraywherex%2==0select(long)x).Sum();returntotal;}[Benchmark]publiclongBenchLINQMethod_Array(){vartotal=numArray.Where(x=>x%2==0).Sum(x=>(long)x);returntotal;}#endregion
#region ListWithCalc
[Benchmark]publiclongBenchForWithCalc_List(){vartotal=0;for(vari=0;i<=numList.Count-1;i++){if(i%2==0)total+=numList[i];}returntotal;}[Benchmark]publiclongBenchForEachWithCalc_List(){vartotal=0;foreach(varnuminnumList){if(num%2==0)total+=num;}returntotal;}[Benchmark]publiclongBenchDoWithCalc_List(){vari=0;vartotal=0;while(i<=numList.Count-1){if(i%2==0)total+=numList[i];i++;}returntotal;}[Benchmark]publiclongBenchDoWhileWithCalc_List(){vari=0;vartotal=0;do{if(i%2==0)total+=numList[i];i++;}while(i<=numList.Count-1);returntotal;}[Benchmark]publiclongBenchLINQQuery_List(){vartotal=(fromxinnumListwherex%2==0select(long)x).Sum();returntotal;}[Benchmark]publiclongBenchLINQMethod_List(){vartotal=numList.Where(x=>x%2==0).Sum(x=>(long)x);returntotal;}#endregion}classProgram{staticvoidMain(string[]args){BenchmarkRunner.Run<LoopBenchmarkTest>();}}}