このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
spmd
、parfor
、および parfeval
からの選択
計算を並列実行するには、spmd
、parfor
、parfeval
、または parfevalOnAll
を使用できます。それぞれの構成では異なる並列プログラミング概念を利用しています。
どのような時に parfor
を使用するか
ループ反復が低速、またはループ反復の回数が多い for
ループがある場合、parfor
ループが有用なことがあります。個々の反復は他のすべての反復から独立していなければなりません。どのような時に parfor を使用するかを決定する際の詳細なヘルプについては、parfor を使用するタイミングの決定を参照してください。
どのような時に spmd
を使用するか
並列コードの通信の実行
計算中にワーカー間で詳細な通信と連携が必要な場合は、spmd
を使用します。parfor
、parfeval
、および parfevalOnAll
では、ワーカー間の通信ができません。spmd
による計算では、関数 spmdSend
、spmdReceive
、および spmdSendReceive
を使用してワーカー間の通信を実行できます。
確信がもてない場合は、"並列コード内で、それぞれの計算をワーカー間での通信なしに完了できるかどうか" を確認します。できる場合は、parfor
または parfeval
を使用します。それ以外の場合は、spmd
を使用します。
分散配列に対する並列コードおよびカスタマイズしたコードの実行
計算で、ワーカー間に分散する大規模配列を扱う場合は、spmd
を使用します。すべてのワーカー上での同時計算、または特定のワーカー上でのカスタマイズされた計算を実行できます。
ワーカーが spmd
ブロックを実行すると、各ワーカーに一意のインデックス spmdIndex
が割り当てられます。これにより、コードを特定のワーカーのみ、および分散配列のターゲット セクションのみで実行するように指定できます。
同期および非同期の作業
parfor
、parfeval
、および spmd
から選択するときには、計算にクライアントとの同期が必要かどうかを検討します。
parfor
と spmd
には同期が必要なため、MATLAB® クライアント上で新規計算の実行がブロックされます。parfeval
には同期が不要なため、クライアントを使用し続けることができます。
関数の他の機能の使用
spmd
と parfeval
には、計算の投入後に使用できる他の機能があります。
spmd
では、spmd
ステートメント内で計算した結果を、クライアントに転送せずに収集できます。クライアントからは、spmd
ステートメント内で代入した変数の値にComposite
オブジェクトとしてアクセスします。詳細については、Composite を使用するワーカー変数へのアクセスを参照してください。parfeval
タスクを投入すると、MATLAB によりタスクの非同期実行がスケジュールされ、投入したタスクの実行が完了する前にFuture
オブジェクトが返されます。Future
オブジェクトは、MATLAB によってスケジュールされたタスクを表します。Future
オブジェクトは、次のようなさまざまな方法で操作できます。
parfor
、parfeval
、および 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
) と行列のサイズ (m
行 m
列の行列) を設定します。試行数を増やすと後の解析で使用する統計値が向上しますが、計算自体には影響しません。
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
に必要な評価あたりのオーバーヘッドは、parfor
や parfeval
より長くなります。このため、この例では、parfor
ループまたは parfeval
を使用する方がより効率的です。
乱数行列の和の計算
次に、乱数行列の和を計算します。これを行うには、parfor
ループでリダクション変数を、parfeval
で計算後の和を、または spmd
で spmdPlus
を使用します。ここでも、試行数 (n
) と行列のサイズ (m
行 m
列の行列) を設定します。
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)')
この計算の場合、spmd
は parfor
ループや parfeval
より速くなります。parfor
ループでリダクション変数を使用すると、各ワーカーではローカルのリダクションを実行してから、最終結果を計算するために部分的な結果をクライアントに送信します。
一方、spmd
は spmdPlus
を 1 回のみ呼び出してグローバルなリダクション演算を実行するため、必要なオーバーヘッドがより少なくなります。したがって計算のリダクション部分のオーバーヘッドは、spmd
で 、parfor
で です。