Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

spmdparfor、および parfeval からの選択

計算を並列実行するには、spmdparforparfeval、または parfevalOnAll を使用できます。それぞれの構成では異なる並列プログラミング概念を利用しています。

どのような時に parfor を使用するか

ループ反復が低速、またはループ反復の回数が多い for ループがある場合、parfor ループが有用なことがあります。個々の反復は他のすべての反復から独立していなければなりません。どのような時に parfor を使用するかを決定する際の詳細なヘルプについては、parfor を使用するタイミングの決定を参照してください。

どのような時に spmd を使用するか

並列コードの通信の実行

計算中にワーカー間で詳細な通信と連携が必要な場合は、spmd を使用します。parforparfeval、および parfevalOnAll では、ワーカー間の通信ができません。spmd による計算では、関数 spmdSendspmdReceive、および spmdSendReceive を使用してワーカー間の通信を実行できます。

確信がもてない場合は、"並列コード内で、それぞれの計算をワーカー間での通信なしに完了できるかどうか" を確認します。できる場合は、parfor または parfeval を使用します。それ以外の場合は、spmd を使用します。

分散配列に対する並列コードおよびカスタマイズしたコードの実行

計算で、ワーカー間に分散する大規模配列を扱う場合は、spmd を使用します。すべてのワーカー上での同時計算、または特定のワーカー上でのカスタマイズされた計算を実行できます。

ワーカーが spmd ブロックを実行すると、各ワーカーに一意のインデックス spmdIndex が割り当てられます。これにより、コードを特定のワーカーのみ、および分散配列のターゲット セクションのみで実行するように指定できます。

同期および非同期の作業

parforparfeval、および spmd から選択するときには、計算にクライアントとの同期が必要かどうかを検討します。

parforspmd には同期が必要なため、MATLAB® クライアント上で新規計算の実行がブロックされます。parfeval には同期が不要なため、クライアントを使用し続けることができます。

関数の他の機能の使用

spmdparfeval には、計算の投入後に使用できる他の機能があります。

  • spmd では、spmd ステートメント内で計算した結果を、クライアントに転送せずに収集できます。クライアントからは、spmd ステートメント内で代入した変数の値に Composite オブジェクトとしてアクセスします。詳細については、Composite を使用するワーカー変数へのアクセスを参照してください。

  • parfeval タスクを投入すると、MATLAB によりタスクの非同期実行がスケジュールされ、投入したタスクの実行が完了する前に Future オブジェクトが返されます。Future オブジェクトは、MATLAB によってスケジュールされたタスクを表します。Future オブジェクトは、次のようなさまざまな方法で操作できます。

    • fetchNext を使用して、使用可能になった結果の収集、または結果が用意できたかのチェックを行う。

    • 関数 cancel を使用して、parfeval の計算の実行を停止する。

    • クライアント上で Future オブジェクトを他の計算に使用する。

parforparfeval、および spmd のパフォーマンスの比較

spmd の使用は、計算のタイプによって parfor ループや parfeval の使用より遅い場合もあれば速い場合もあります。オーバーヘッドが parfor ループ、parfeval、および spmd の相対的なパフォーマンスに影響します。

一連のタスクでは、通常、parfor および parfeval は次の条件下で spmd より優れたパフォーマンスを示します。

  • タスクあたりの計算時間が確定的でない。

  • タスクあたりの計算時間が一様でない。

  • 各タスクから返されるデータが小さい。

parfeval は次の場合に使用します。

  • 計算をバックグラウンドで実行する。

  • 各タスクが他のタスクに依存する。

この例では、ソフトウェアで parfor ループ、parfeval、および spmd を使用して行列演算が実行される際の速さを調べます。

まず、プロセス ワーカーの並列プール p を作成します。

p = parpool("Processes");
Starting parallel pool (parpool) using the 'Processes' profile ...
Connected to parallel pool with 6 workers.

乱数行列の計算

ソフトウェアで parfor ループ、parfeval、および spmd を使用して乱数行列を生成できる速さを調べます。試行数 (n) と行列のサイズ (mm 列の行列) を設定します。試行数を増やすと後の解析で使用する統計値が向上しますが、計算自体には影響しません。

m = 1500;
n = 20;

次に、parfor ループを使用して、各ワーカーで rand(m) を 1 回実行します。n 回の試行について、それぞれの時間を測定します。

parforTime = zeros(n,1);
for i = 1:n
    tic;
    mats = cell(1,p.NumWorkers);
    parfor N = 1:p.NumWorkers
      mats{N} = rand(m);
    end
    parforTime(i) = toc;
end

次に、parfeval を使用して、各ワーカーで rand(m) を 1 回実行します。n 回の試行について、それぞれの時間を測定します。

parfevalTime = zeros(n,1);
for i = 1:n
    tic;
    f(1:p.NumWorkers) = parallel.FevalFuture;
    for N = 1:p.NumWorkers
      f(N) = parfeval(@rand,1,m);
    end
    mats = fetchOutputs(f);
    parfevalTime(i) = toc;
    clear f
end

最後に、spmd を使用して、各ワーカーで rand(m) を 1 回実行します。spmdCat を使用して各ワーカーの mat の値を連結して配列 mats を生成し、ワーカー 1 に保存します。ワーカー、および spmd を使ってワーカーでコマンドを実行する方法の詳細については、複数のデータセットでの単一プログラムの実行を参照してください。n 回の試行について、それぞれの時間を測定します。

spmdTime = zeros(n,1);
for i = 1:n
    tic;
    spmd
        mat = rand(m);
        mats = spmdCat({mat}, 1, 1);
    end
    allMats = mats{1};
    spmdTime(i) = toc;
end

rmoutliers を使用して、各試行から外れ値を削除します。次に、boxplot を使用して時間を比較します。

% Hide outliers
boxData = rmoutliers([parforTime parfevalTime spmdTime]);

% Plot data
boxplot(boxData, 'labels',{'parfor','parfeval','spmd'}, 'Symbol','')
ylabel('Time (seconds)')
title('Make n Random Matrices (m-by-m)')

通常、spmd に必要な評価あたりのオーバーヘッドは、parforparfeval より長くなります。このため、この例では、parfor ループまたは parfeval を使用する方がより効率的です。

乱数行列の和の計算

次に、乱数行列の和を計算します。これを行うには、parfor ループでリダクション変数を、parfeval で計算後の和を、または spmdspmdPlus を使用します。ここでも、試行数 (n) と行列のサイズ (mm 列の行列) を設定します。

m = 1500;
n = 20;

次に、parfor ループを使用して、各ワーカーで rand(m) を 1 回実行します。リダクション変数を使用して和を計算します。n 回の試行について、それぞれの時間を測定します。

parforTime = zeros(n,1);
for i = 1:n
    tic;
    result = 0;
    parfor N = 1:p.NumWorkers
      result = result + rand(m);
    end
    parforTime(i) = toc;
end

次に、parfeval を使用して、各ワーカーで rand(m) を 1 回実行します。fetchOutputs を使用してすべての行列を取得してから、sum を使用します。n 回の試行について、それぞれの時間を測定します。

parfevalTime = zeros(n,1);
for i = 1:n
    tic;
    f(1:p.NumWorkers) = parallel.FevalFuture;
    for N = 1:p.NumWorkers
      f(N) = parfeval(@rand,1,m);
    end
    result = sum(fetchOutputs(f));
    parfevalTime(i) = toc;
    clear f
end

最後に、spmd を使用して、各ワーカーで rand(m) を 1 回実行します。spmdPlus を使用して、すべての行列を合計します。結果を最初のワーカーにのみ送信するには、オプションのターゲット ワーカー引数を 1 に設定します。n 回の試行について、それぞれの時間を測定します。

spmdTime = zeros(n,1);
for i = 1:n
    tic;
    spmd
        r = spmdPlus(rand(m), 1);
    end
    result = r{1};
    spmdTime(i) = toc;
end

rmoutliers を使用して、各試行から外れ値を削除します。次に、boxplot を使用して時間を比較します。

% Hide outliers
boxData = rmoutliers([parforTime parfevalTime spmdTime]);

% Plot data
boxplot(boxData, 'labels',{'parfor','parfeval','spmd'}, 'Symbol','')
ylabel('Time (seconds)')
title('Sum of n Random Matrices (m-by-m)')

この計算の場合、spmdparfor ループや parfeval より速くなります。parfor ループでリダクション変数を使用すると、各ワーカーではローカルのリダクションを実行してから、最終結果を計算するために部分的な結果をクライアントに送信します。

一方、spmdspmdPlus を 1 回のみ呼び出してグローバルなリダクション演算を実行するため、必要なオーバーヘッドがより少なくなります。したがって計算のリダクション部分のオーバーヘッドは、spmdO(n2)parforO(mn2) です。

参考

| |

関連するトピック