[C #] I tried to verify the speed of the loop statement Part 2

5 minute read

Last time, I summarized the speed verification of loop statements in C #. Since there were many places where the verification method was immature, we will carry out verification using BenchmarkDotNet introduced by @Midoliy this time.

To carry out

  1. Prepare an array and list with 100 million elements.
  2. Verify the prepared array and list.
  3. Simply spin around.
  4. Add multiples of 2 while turning around.

Target loop statement

  1. for
  2. foreach
  3. do
  4. do-while
  5. LINQ (Query format): Only add-in verification is performed
  6. LINQ (Method format): Only add-in verification is performed

result

Simply spin around (array)

                  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 |

Simply spin around (list)

                  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 |  * The reason why the speed of foreach changes so much between arrays and lists was very easy to understand from @ Tokeiya's [for and foreach for arrays](https://qiita.com/Tokeiya/items/5f69f0b0233c62967820).

Addition of multiples of 2 (array)

                  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 | ### Addition of multiples of 2 (list)
                  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)

Validation source

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;  //Element count
        private static readonly int[] numArray;             //Validation array
        private static readonly List<int> numList;          //Validation list

        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>();
        }
    }
}