ネストしたアルゴリズムを使用したスケーラビリティーの向上#
フローグラフのスケーラビリティーを向上させる強力な方法の 1 つは、ノードボディー内に他の並列アルゴリズムをネストすることです。これにより、フローグラフを調整言語として使用し、グラフのレベルで最も粗い粒度の並列処理を表現し、その中により細かい粒度の並列処理をネストできます。
以下の例では、5 つのノードが作成されます。ファイルから行列のシーケンスを読み取る input_node、matrix_source、これらの行列を受け取り、各要素に関数を適用して 2 つの新しい行列を生成する 2 つの function_nodes、n1 と n2、そして結果の行列を処理する 2 つの最後の function_nodes、n1_sink および n2_sink です。matrix_source は n1 と n2 の両方に接続されています。ノード n1 は n1_sink に接続され、n2 は n2_sink に接続されます。n1 と n2 のラムダ式では、parallel_for を使用して、関数を行列の要素に並列に適用します。関数 read_next_matrix、f1、f2、consume_f1、consume_f2 は以下では提供されません。
graph g;
input_node< double * > matrix_source( g, [&]( oneapi::tbb::flow_control &fc ) -> double* {
double *a = read_next_matrix();
if ( a ) {
return a;
} else {
fc.stop();
return nullptr;
}
} );
function_node< double *, double * > n1( g, unlimited, [&]( double *a ) -> double * {
double *b = new double[N];
parallel_for( 0, N, [&](int i) {
b[i] = f1(a[i]);
} );
return b;
} );
function_node< double *, double * > n2( g, unlimited, [&]( double *a ) -> double * {
double *b = new double[N];
parallel_for( 0, N, [&](int i) {
b[i] = f2(a[i]);
} );
return b;
} );
function_node< double *, double * > n1_sink( g, unlimited,
[]( double *b ) -> double * {
return consume_f1(b);
} );
function_node< double *, double * > n2_sink( g, unlimited,
[]( double *b ) -> double * {
return consume_f2(b);
} );
make_edge( matrix_source, n1 );
make_edge( matrix_source, n2 );
make_edge( n1, n1_sink );
make_edge( n2, n2_sink );
matrix_source.activate();
g.wait_for_all();