【C#】ループステートメントの速度を検証してみた　その２

[前回](https://qiita.com/5umerag1/items/9a4e0204eeca49e42b93)、C#におけるループステートメントの速度検証をまとめてみました。検証方法が未熟な箇所が多々あったため、今回は@Midoliyさんにご紹介いただきました`BenchmarkDotNet`を用いて検証を実施します。

## 実施すること
1. 1億個の要素を持った配列およびリストを用意する。
2. 準備した配列、リストに対して検証する。
  1. 単純にぐるぐる回す。
  2. ぐるぐる回しながら2の倍数を足し込んでいく。

## 対象のループステートメント
1. for
2. foreach
3. do
4. do-while
5. LINQ(Query形式)：足し込み検証のみ実施
6. 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](https://qiita.com/Tokeiya/items/5f69f0b0233c62967820)が非常にわかりやすかったです。


### 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)
```

## 検証ソース
```C#
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Collections.Generic;
using System.Linq;

namespace Benchmarks
{
    public class LoopBenchmarkTest
    {
        private static readonly int listCnt = 100_000_000;  // 要素数
        private static readonly int[] numArray;             // 検証配列
        private static readonly List<int> numList;          // 検証リスト

        static LoopBenchmarkTest()
        {
            numArray = Enumerable.Range(0, listCnt).ToArray();
            numList = new List<int>(numArray);
        }

#region Array
        [Benchmark]
        public long BenchFor_Array()
        {
            for (var i = 0; i <= numArray.Length - 1; i++) {}
            return 0;
        }

        [Benchmark]
        public long BenchForEach_Array()
        {
            foreach (var num in numArray) {}
            return 0;
        }

        [Benchmark]
        public long BenchDo_Array()
        {
            var i = 0;
            while (i <= numArray.Length - 1)
            {
                i++;
            }
            return 0;
        }

        [Benchmark]
        public long BenchDoWhile_Array()
        {
            var i = 0;
            do
            {
                i++;
            }
            while (i <= numArray.Length - 1);
            return 0;
        }
#endregion

#region List
        [Benchmark]
        public long BenchFor_List()
        {
            for (var i = 0; i <= numList.Count - 1; i++) {}
            return 0;
        }

        [Benchmark]
        public long BenchForEach_List()
        {
            foreach (var num in numList) {}
            return 0;
        }

        [Benchmark]
        public long BenchDo_List()
        {
            var i = 0;
            while (i <= numList.Count - 1)
            {
                i++;
            }
            return 0;
        }

        [Benchmark]
        public long BenchDoWhile_List()
        {
            var i = 0;
            do
            {
                i++;
            }
            while (i <= numList.Count - 1);
            return 0;
        }
#endregion

#region ArrayWithCalc
        [Benchmark]
        public long BenchForWithCalc_Array()
        {
            var total = 0;
            for (var i = 0; i <= numArray.Length - 1; i++)
            {
                if (i % 2 == 0)
                    total += numArray[i];
            }
            return total;
        }

        [Benchmark]
        public long BenchForEachWithCalc_Array()
        {
            var total = 0;
            foreach (var num in numArray)
            {
                if (num % 2 == 0)
                    total += num;
            }
            return total;
        }

        [Benchmark]
        public long BenchDoWithCalc_Array()
        {
            var i = 0;
            var total = 0;
            while (i <= numArray.Length - 1)
            {
                if (i % 2 == 0)
                    total += numArray[i];
                i++;
            }
            return total;
        }

        [Benchmark]
        public long BenchDoWhileWithCalc_Array()
        {
            var i = 0;
            var total = 0;
            do
            {
                if (i % 2 == 0)
                    total += numArray[i];
                i++;
            }
            while (i <= numArray.Length - 1);
            return total;
        }

        [Benchmark]
        public long BenchLINQQuery_Array()
        {
            var total = (
                from x in numArray
                where x % 2 == 0
                select (long)x
                ).Sum();
            return total;
        }

        [Benchmark]
        public long BenchLINQMethod_Array()
        {
            var total = numArray
                .Where(x => x % 2 == 0)
                .Sum(x => (long)x);
            return total;
        }
#endregion

#region ListWithCalc
        [Benchmark]
        public long BenchForWithCalc_List()
        {
            var total = 0;
            for (var i = 0; i <= numList.Count - 1; i++)
            {
                if (i % 2 == 0)
                    total += numList[i];
            }
            return total;
        }

        [Benchmark]
        public long BenchForEachWithCalc_List()
        {
            var total = 0;
            foreach (var num in numList)
            {
                if (num % 2 == 0)
                    total += num;
            }
            return total;
        }

        [Benchmark]
        public long BenchDoWithCalc_List()
        {
            var i = 0;
            var total = 0;
            while (i <= numList.Count - 1)
            {
                if (i % 2 == 0)
                    total += numList[i];
                i++;
            }
            return total;
        }

        [Benchmark]
        public long BenchDoWhileWithCalc_List()
        {
            var i = 0;
            var total = 0;
            do
            {
                if (i % 2 == 0)
                    total += numList[i];
                i++;
            }
            while (i <= numList.Count - 1);
            return total;
        }

        [Benchmark]
        public long BenchLINQQuery_List()
        {
            var total = (
                from x in numList
                where x % 2 == 0
                select (long)x
                ).Sum();
            return total;
        }

        [Benchmark]
        public long BenchLINQMethod_List()
        {
            var total = numList
                .Where(x => x % 2 == 0)
                .Sum(x => (long)x);
            return total;
        }
#endregion

    }

    class Program
    {
        static void Main(string[] args)
        {
            BenchmarkRunner.Run<LoopBenchmarkTest>();
        }
    }
}
```