Forループ処理速度評価 (C++ , C#)

C++のParallel.For メソッド、C#のtbb::Parallel_Forクラスについて、並列処理の速度比較を行う

目的

今後製作する画像処理アプリケーションにて、画像処理部分はC++、GUIはC#で実装する予定である。
今までC#ではParallel.Forを使用した経験はあるが、C++で並列化したい場合に使われるtbb::parallel_forについて評価をし、差異がどのようにあるか知る。

実施方法

C#、C++で1回当たり約1msの処理をシングルタスク、並列処理両方で任意の回数ループさせるコードを準備し、それぞれ処理時間を調べる。
PCの仕様は以下

  • OS … Windows10
  • CPU … intel core i7-8700 3.2GHz 6コア 12スレッド
  • メモリ … 16GB

評価用コード

C++

#include <iostream>
#include <vector>
#include <oneapi/tbb.h>

#pragma once


int main()
{
	int t = 300;
	std::vector<double> a(1800000);

	//時間計測 シングルタスク
	tbb::tick_count t0 = tbb::tick_count::now();
	//ここから
	for (int i = 0; i < t; i++) {
		// 1回あたり約1mmsecの処理
		for (int i = 0; i < a.size(); i++)
		{
			a[i] = 1.001;
		}
	}
	//ここまで 
	tbb::tick_count t1 = tbb::tick_count::now();

	double period = (t1 - t0).seconds() * 1000;
	std::cout << "Sタスク: " << period << " ms" << std::endl;

	//時間計測 並列処理
	t0 = tbb::tick_count::now();
	//ここから
	tbb::parallel_for(tbb::blocked_range<int>(0, t),
		[&](tbb::blocked_range <int> r) {
			for (int i = r.begin(); i < r.end(); i++) {
				//1回あたり約1mmsecの処理
				for (int i = 0; i < a.size(); i++)
				{
					a[i] = 1.001;
				}

			}
		});
	t1 = tbb::tick_count::now();
	//ここまで
	period = (t1 - t0).seconds() * 1000;
	std::cout << "Mタスク: " << period << " ms" << std::endl;
}
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace paralleltest_cs
{
    class Program
    {
        static void Main(string[] args)
        {
            int t = 100;
            double[] a = new double[550000];
            //シングルタスク
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            //ここから
            for (int j = 0; j < t; j++)
            {
                //約1msの処理
                for (int i = 0; i < a.Length; i++)
                {
                    a[i] = 1.001;
                }
            }
            //ここまで
            sw.Stop();
            double period = sw.ElapsedTicks /10000.0;
            Console.Write("Sタスク: "+period+" ms\n");

            //並列処理
            sw.Restart();
            Parallel.For(0, t, j =>
             {
                 for(int i = 0; i < a.Length; i++) { 
                     a[i] = 1.001;
                 }
             });
            //ここまで
            sw.Stop();

            period = sw.ElapsedTicks / 10000.0;
            Console.Write("Mタスク: "+period+" ms\n");
            Thread.Sleep(10000);
            
        }
    }

結果

処理時間の測定結果は以下の表及びグラフに表示する。

回数が1000回以上ではC++(tbb)、C#ともに並列化で6倍程度の速度がでている。
1000回以下ではC++(tbb)の方が速度が出るようである。
C++ tbbライブラリは、ヘッダファイル、インクルード、dllファイルの保存等設定が必要なため面倒であるが、処理時間が1s以下で高速化したい場合はtbbライブラリを使用した方が効果がある。

参考

  • intel Threading Building Blocks … Wikipedia
  • ダウンロードページ … GitHub