C/C++で並列コンピューティング(スレッド・ライブラリ編)の続編。今度はC/C++の並列ライブラリを用いて円周率の近似計算コードを書いてみた。タスク割り当てやスレッドの起動を自分でやる必要がないので簡潔に記述できる。
- OpenMP
- Intel TBB (Threading Building Brocks)
- Microsoft PPL (Parallel Patterns Library)
##OpenMP
既存コード中のループにpragmaで並列化を指示するだけ。簡単。
#include <omp.h>
// PI近似計算 (OpenMP)
double compute_pi_by_openmp(const int num_of_partitions)
{
if (num_of_partitions < 1) return -1.;
double width = 1. / (double)num_of_partitions;
double height = 0.;
double middle = 0.;
double sum = 0.;
double pi = 0.;
int index = 0;
#pragma omp parallel for private(middle, height) reduction(+:sum)
for (index = 0; index < num_of_partitions; index++) {
middle = (index + 0.5) * width;
height = 4. / (1. + middle * middle);
sum += height;
}
pi = width * sum;
return pi;
}
##Intel TBB
###parallel_reduce()
の場合
#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>
#include <tbb/partitioner.h>
#include <functional>
// PI近似計算 (Intel TBB)
double compute_pi_by_tbb(const int num_of_partitions)
{
if (num_of_partitions < 1) return -1.;
const double width = 1. / static_cast<double>(num_of_partitions);
double sum = 0.;
sum = tbb::parallel_reduce(
tbb::blocked_range<int>(0, num_of_partitions),
0.,
[width](const tbb::blocked_range<int>& range, double value)->double {
for (int i = range.begin(); i != range.end(); i++) {
double middle = (i + 0.5) * width;
double height = 4. / (1. + middle * middle);
value += height;
}
return value;
},
std::plus<double>(),
tbb::auto_partitioner()
);
double pi = sum * width;
return pi;
}
###parallel_for()
の場合
#include <tbb/parallel_for.h>
#include <tbb/combinable.h>
#include <tbb/blocked_range.h>
#include <functional>
//------------------------------------------------------------------------------
// PI近似計算 (Intel TBB)
//------------------------------------------------------------------------------
double compute_pi_by_tbb2(const int num_of_partitions)
{
if (num_of_partitions < 1) return -1.;
const double width = 1. / static_cast<double>(num_of_partitions);
tbb::combinable<double> sum;
tbb::parallel_for(tbb::blocked_range<int>(0, num_of_partitions),
[width, &sum](const tbb::blocked_range<int>& range) {
double sum_local = 0.;
for (int i = range.begin(); i != range.end(); i++) {
double middle = (i + 0.5) * width;
double height = 4. / (1. + middle * middle);
sum_local += height;
}
sum.local() += sum_local;
});
double pi = sum.combine(std::plus<double>()) * width;
return pi;
}
(2014/1/12) TBB2.2以降は明示的な初期化 tbb::task_schedular_init
が不要とのことですのでコードから削除しました。また、下記のPPLでの例と同等となるようにtbb::parallel_for()
の例も追加しました。
##Microsoft PPL
#include <ppl.h>
// PI近似計算 (Microsoft PPL)
double compute_pi_by_ppl(const int num_of_partitions)
{
if (num_of_partitions < 1) return -1.;
const double width = 1. / static_cast<double>(num_of_partitions);
concurrency::combinable<double> sum;
concurrency::parallel_for<int>(0, num_of_partitions, [&sum, width](int i){
double middle = (i + 0.5) * width;
double height = 4. / (1. + middle * middle);
sum.local() += height;
});
double pi = sum.combine(std::plus<double>()) * width;
return pi;
}
C/C++で並列コンピューティング(GPGPU編)に続く、かも。