ネストしたアルゴリズムを使用したスケーラビリティーの向上

ネストしたアルゴリズムを使用したスケーラビリティーの向上#

フローグラフのスケーラビリティーを向上させる強力な方法の 1 つは、ノードボディー内に他の並列アルゴリズムをネストすることです。これにより、フローグラフを調整言語として使用し、グラフのレベルで最も粗い粒度の並列処理を表現し、その中により細かい粒度の並列処理をネストできます。

以下の例では、5 つのノードが作成されます。ファイルから行列のシーケンスを読み取る input_nodematrix_source、これらの行列を受け取り、各要素に関数を適用して 2 つの新しい行列を生成する 2 つの function_nodesn1n2、そして結果の行列を処理する 2 つの最後の function_nodesn1_sink および n2_sink です。matrix_sourcen1n2 の両方に接続されています。ノード n1n1_sink に接続され、n2n2_sink に接続されます。n1n2 のラムダ式では、parallel_for を使用して、関数を行列の要素に並列に適用します。関数 read_next_matrixf1f2consume_f1consume_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();