#include "tbb/parallel_do.h"
template<typename InputIterator, typename Body>
void parallel_do( InputIterator first, InputIterator last,
Body body[, task_group_context& group] );
parallel_do(first,last,body) は、半開区間 [first,last) の関数オブジェクト・ボディーに適用されます。 項目は並列に処理されます。追加の作業項目は、 parallel_do_feeder 型の第 2 引数がある場合、ボディーによって追加できます。 body(x) が入力シーケンスまたは parallel_do_feeder::add メソッドによって追加されたすべての項目 x について返されると、関数は終了します。
入力イテレーターの要件は、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() を同時に呼び出します。 フィーダーの署名は、作業項目の追加を許可します。 |
|
T( const T& ) |
作業項目をコピーします。 |
|
~T::T() |
作業項目を破棄します。 |
例えば、C++ 標準化仕様書のセクション 20.3 で定義されている単項関数オブジェクトは、B の要件をモデル化します。
operator() の引数が 1 つの形式と引数が 2 つの形式の両方を定義することはできません。
すべての項目がランダムアクセスのない入力ストリームからの項目である場合、parallel_do の並列処理はスケーラブルではありません。スケーリングを達成するには、次のいずれかを行います。
ランダムアクセス・イテレーターを使用して入力ストリームを指定します。
ボディーが作業の断片を 2 つ以上追加するようなアルゴリズムを設計します。
代わりに parallel_for を使用します。
速度を向上するには、B::operator() の粒度は少なくともほぼ 100,000 クロックサイクルである必要があります。 粒度が小さい場合、parallel_do の内部オーバーヘッドが大きくなります。
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);
}
}
};