[kaze's test] プログラミングメモ →目次

parallel_invoke()関数

並列パターン ライブラリ (PPL)

パラメーターとして渡された関数オブジェクトを並列実行し、実行が完了するまでブロックします。各関数オブジェクトは、ラムダ式、関数へのポインター、またはシグネチャ void operator()() を持つ関数呼び出し演算子をサポートするオブジェクトになります。

 
プロトタイプ:

template < 
typename _Function1,
typename _Function2
>
void parallel_invoke(
const _Function1& _Func1,
const _Function2& _Func2
);
template <
typename _Function1,
typename _Function2,
typename _Function3
>
void parallel_invoke(
const _Function1& _Func1,
const _Function2& _Func2,
const _Function3& _Func3
);
... ... ...
... ... ...
template <
typename _Function1,
typename _Function2,
typename _Function3,
typename _Function4,
typename _Function5,
typename _Function6,
typename _Function7,
typename _Function8,
typename _Function9,
typename _Function10
>
void parallel_invoke(
const _Function1& _Func1,
const _Function2& _Func2,
const _Function3& _Func3,
const _Function4& _Func4,
const _Function5& _Func5,
const _Function6& _Func6,
const _Function7& _Func7,
const _Function8& _Func8,
const _Function9& _Func9,
const _Function10& _Func10
);
パラメーターの意味:
_Function1(2,3,..,10)
並列実行される 10 番目の関数オブジェクトの型。 

_Func1(2,3,..,10)
並列実行される最初の関数オブジェクト。


例:関数ポインター形式で1~10000の間の素数を数える処理、シグネチャ void operator()()で1~900000の間の偶数を数える処理、ラムダ式で1~900000の間の奇数を数える処理 をparallel_invoke()関数で、並列実行させます。直列処理もして、所用時間を統計、表示します。

#include "stdafx.h"
#include 
#include 
#include 

using namespace Concurrency;
using namespace std;

// Calls the provided work function and returns the number of milliseconds 
// that it takes to call that function.
template 
__int64 time_call(Function&& f)
{
   __int64 begin = GetTickCount();
   f();
   return GetTickCount() - begin;
}

// Determines whether the input value is prime.
bool is_prime(int n)
{
   if (n < 2)
      return false;
   for (int i = 2; i < n; ++i)
   {
      if ((n % i) == 0)
         return false;
   }
   return true;
}

// Computes the count of prime numbers in the range [start, end).
unsigned int count_primes(int start, int end)
{
   unsigned int count = 0u;
   for (int n = start; n < end; ++n)
   {
      if (is_prime(n))
         ++count;
   }
   return count;
}

// Function object (functor) class that count the even numbers.
template
class CountEvenFunctor
{
private:
	Type* pCount;
	Type start;
	Type end;

public:
   // Constructor initialization
	CountEvenFunctor ( const Type* _pVal, const Type _start, const Type _end )
	{
		pCount = (unsigned int *)_pVal;
		start = _start;
		end = _end;
	}

	void operator()() const
	{
		for (Type n = start; n < end; n ++)
		{
			if (n % 2 == 0)
				*pCount += 1;
		}	
	}
};

int _tmain()
{
   // The count of prime numbers in various ranges.
   unsigned int prime_count;
   unsigned int even_count;
   unsigned int odd_count;

   // The total time to compute the count of prime numbers
   // in all ranges.
   __int64 total_elapsed;

   prime_count = 0;
   even_count = 0;
   odd_count = 0;

   wcout << L"serial version: " << endl;

   total_elapsed = time_call([&] 
   {
      __int64 elapsed;

      elapsed = time_call([&] {prime_count = count_primes(0, 10000);});
      wcout << L"count of prime numbers in [0, 10000): " 
            << prime_count << L" (" << elapsed << L" ms)" << endl;

      elapsed = time_call(CountEvenFunctor(&even_count, 0, 900000));
      wcout << L"count of even numbers in [0, 900000): " 
            << even_count << L" (" << elapsed << L" ms)" << endl;

      elapsed = time_call([&] {
			odd_count = 0;
			for (int n = 0; n < 900000; n ++)
			{
				if (n % 2 == 1)
					odd_count += 1;
			}							
		});
      wcout << L"count of odd numbers in [0, 900000): " 
            << odd_count << L" (" << elapsed << L" ms)" << endl;
   });
   wcout << L"total time: " << total_elapsed << L" ms" << endl << endl;

   // Now compute the counts in parallel for the same ranges.

   prime_count = 0;
   even_count = 0;
   odd_count = 0;

   wcout << L"parallel version: " << endl;

   total_elapsed = time_call([&] {
      parallel_invoke(
         [&] {prime_count = count_primes(0, 10000);},
         CountEvenFunctor(&even_count, 0, 900000),
         [&] {
			odd_count = 0;
			for (int n = 0; n < 900000; n ++)
			{
				if (n % 2 == 1)
					odd_count += 1;
			}							
		}
      );
   });

   wcout << L"count of prime numbers in [0, 10000): " << prime_count << endl;
   wcout << L"count of even numbers in [0, 900000): " << even_count << endl;
   wcout << L"count of odd numbers in [0, 900000): " << odd_count << endl;
  

   wcout << L"total time: " << total_elapsed << L" ms" << endl << endl;

   getchar();
}
出力:
serial version:
count of prime numbers in [0, 10000): 1229 (31 ms)
count of even numbers in [0, 900000): 450000 (16 ms)
count of odd numbers in [0, 900000): 450000 (16 ms)
total time: 63 ms

parallel version:
count of prime numbers in [0, 10000): 1229
count of even numbers in [0, 900000): 450000
count of odd numbers in [0, 900000): 450000
total time: 31 ms