2016年9月2日金曜日

C#でParallelクラスを使って並列処理を高速化を速度計測

Parallelクラスを使って並列処理を高速化してみました。

環境としては、SurfacePro4でCPUは、i5です。
テストコードは、次の汚れきった目も当てられないコードになっています。

試したのは、foreach文、for文、Parallel.ForEach,Parallel.For(スレッド数は、デフォルト、8,4,2)の10種類です。

結果としては、予想通り、コア数と同程度が良いみたいですね。
ちなみに、スレッド数指定しない場合には、いくつで動くのか、わかる人いたら教えてください。
お願いします。

コード

/// <summary>
/// テスト実施
/// </summary>
/// <remarks>
/// 同じこといっぱい書きたくなかったのと、
/// クラス用意するのがいやだったのと、
/// 関数化するのが面倒だったので、
/// 汚コードです。
/// </remarks>
/// <param name="args"></param>
static void Main(string[] args)
{
    var count = 1000;
    var target = Enumerable.Range(0, count).ToList();
    var sw = new Stopwatch();
    var results = new List<String>();
    var stringWidth = 40;
    var option = new ParallelOptions();
    // 結果保持のためのAction
    var ResultAdd = new Action<String, TimeSpan>((msg, ellapsed) =>
        {
            results.Add(
                    String.Format(
                    msg, sw.Elapsed).PadLeft(stringWidth));
        });
    // 匿名配列で表示メッセージと実行処理を登録
    var testMethod = new[]
        {
            // foreachで回す
            new {
                Msg ="foreach:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    foreach (var i in list)
                    {
                        Console.WriteLine(WeightMethod(i));
                    }
                })
            },
            // forで回す
            new {
                Msg ="for:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    for (Int32 i = 0; i < count; i++)
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    }
                })
            },
            // Parallel.ForEachで回す(オプション指定なし)
            new {
                Msg ="Parallel.ForEach:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    Parallel.ForEach(list, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし)
            new {
                Msg ="Parallel.For:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    Parallel.For(0, count, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
            // Parallel.ForEachで回す(オプション指定:8)
            new {
                Msg ="Parallel.ForEach8:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 8;
                    Parallel.ForEach( list, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし:8)
            new {
                Msg ="Parallel.For8:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 8;
                    Parallel.For( 0, count, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
            // Parallel.ForEachで回す(オプション指定:4)
            new {
                Msg ="Parallel.ForEach4:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 4;
                    Parallel.ForEach( list, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし:4)
            new {
                Msg ="Parallel.For4:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 4;
                    Parallel.For( 0, count, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
            // Parallel.ForEachで回す(オプション指定:2)
            new {
                Msg ="Parallel.ForEach2:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 2;
                    Parallel.ForEach( list, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし:2)
            new {
                Msg ="Parallel.For2:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 2;
                    Parallel.For( 0, count, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
        };
    for (var id = 0; id < testMethod.Length; id++)
    {
        sw.Reset();
        sw.Start();
        // 実行
        testMethod[id].Method(target);
        sw.Stop();
        // 結果書き込み
        ResultAdd(testMethod[id].Msg, sw.Elapsed);
    }
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}
/// <summary>
/// 重たい処理もどき
/// </summary>
/// <remarks>
/// なんでもよい。
/// </remarks>
/// <param name="count"></param>
/// <returns></returns>
static UInt64 WeightMethod(Int32 count)
{
    var ret = 0UL;
    var max = 10000000 - count;
    for (var i = 0U; i < max; i++)
    {
        ret += i;
        ret -= i;
    }
    return ret;
}


結果
 

                foreach:00:00:36.3392310
                    for:00:00:36.3863514
       Parallel.ForEach:00:00:17.7727370
           Parallel.For:00:00:17.3482534
      Parallel.ForEach8:00:00:17.5221452
          Parallel.For8:00:00:18.8532388
      Parallel.ForEach4:00:00:16.3212531
          Parallel.For4:00:00:16.3745319
      Parallel.ForEach2:00:00:20.8530706
          Parallel.For2:00:00:20.0480644

0 件のコメント:

コメントを投稿