作業項目を並列に処理するテンプレート関数。
#include "tbb/parallel_do.h"
template<typename InputIterator, typename Body> void parallel_do( InputIterator first, InputIterator last, Body body[, task_group_context& group] ); template<typename Container, typename Body> void parallel_do( Container c, Body body[, task_group_context& group] );
parallel_do テンプレートには 2 つの形式があります。
シーケンス形式 parallel_do(first,last,body) は、シーケンス [first,last) の関数オブジェクト・ボディーに適用されます。項目は並列に処理されます。追加の作業項目は、parallel_do_feeder 型の第 2 引数がある場合、ボディーによって追加できます。body(x) が入力シーケンスまたは parallel_do_feeder::add メソッドによって追加されたすべての項目 x について返されると、関数は終了します。
コンテナー形式 parallel_do(c,body) は、parallel_do(std::begin(c),std::end(c),body) と等価です。
入力イテレーターの要件は、ISO C++ 標準のセクション 24.1 で定義されています。以下の表は、Body 型の要件を示しています。
擬似署名 |
意味 |
---|---|
B::operator()( cv-qualifiers T& item, parallel_do_feeder<T>& feeder ) const または B::operator()(cv-qualifiers T& item ) const |
item を処理します。parallel_do テンプレートは、同じ this で item が異なる operator() を同時に呼び出します。 フィーダーの署名は、作業項目の追加を許可します。 警告operator() の引数が 1 つの形式と引数が 2 つの形式の両方を定義することはできません。 |
T( const T& ) |
作業項目をコピーします。 |
~T::T() |
作業項目を破棄します。 |
例えば、C++ 標準化仕様書のセクション 20.3 で定義されている単項関数オブジェクトは、B の要件をモデル化します。
優れたパフォーマンスを得るには、B::operator() の粒度を ~100,000 クロックサイクル程度にします。クロックサイクルが少ない場合、parallel_do のオーバーヘッドがパフォーマンスの利点よりも上回ることがあります。
すべての項目がランダムアクセスのない入力ストリームからの項目である場合、parallel_do の並列処理はスケーラブルではありません。スケーリングを達成するには、次のいずれかを行います。
ランダムアクセス・イテレーターを使用して入力ストリームを指定します。parallel_for を使用することも検討してください。
ボディーが作業の断片を 2 つ以上追加するようなアルゴリズムを設計します。
task_group_context オブジェクトを渡して、タスクがこのグループで実行されるようなアルゴリズムにすることができます。デフォルトでは、アルゴリズムは自身がバインドされているグループで実行されます。
次のコードは、引数が 2 つの形式の operator() のボディーを示します。
struct MyBody { void operator()(item_t item, parallel_do_feeder<item_t>& feeder ) { for each new piece of work implied by item do { item_t new_item = initializer; feeder.add(new_item); } } };