いつバリアを使用する必要があるのでしょうか。たとえば、スキャッター/ギャザーの前/後に必要ですか?または、OMPIはすべてのプロセスが分散/収集する前にそのポイントに到達していることを確認する必要がありますか?同様に、ブロードキャスト後、すべてのプロセスがメッセージをすでに受信することを期待できますか?
MPI MPI-3.0より前のすべての集合操作はブロックされます。つまり、返された後に渡されたすべてのバッファを使用しても安全です。特に、これはすべてのデータが受信されたときに(ただし、すべてのデータが送信されたことを意味するわけではありません!)したがって、すべてのバッファーが既に有効である場合、集合操作の前後にMPI_Barrierは必要ありません(または非常に役立ちます)。
また、MPI_Barrierは非ブロッキング呼び出しを魔法のように待機しないことに注意してください。非ブロッキング送信/受信を使用し、両方のプロセスが送信/受信ペアの後にMPI_Barrierで待機する場合、プロセスがMPI_Barrierの後にすべてのデータを送信/受信したことは保証されません。代わりにMPI_Wait(およびフレンド)を使用してください。したがって、次のコードにはエラーが含まれています。
/* ERRORNOUS CODE */
Code for Process 0:
Process 0 sends something using MPI_Isend
MPI_Barrier(MPI_COMM_WORLD);
Process 0 uses buffer passed to MPI_Isend // (!)
Code for Process 1:
Process 1 recvs something using MPI_Irecv
MPI_Barrier(MPI_COMM_WORLD);
Process 1 uses buffer passed to MPI_Irecv // (!)
(!)
でマークされた両方の行は安全ではありません!
MPI_Barrierは、ごく一部の場合にのみ役立ちます。ほとんどの場合、プロセスが同期しているかどうかは気にしません。ブロックと非ブロックの呼び出しについてよく読んでください!
MPI_Barrier
の用途の1つは、たとえば、MPIを使用してアクセスされないファイルシステムなどの外部リソースへのアクセスを制御することです。たとえば、各プロセスがファイルに順番にデータを書き込むようにするには、次のようにします。
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
for ( int ii = 0; ii < size; ++ii ) {
if ( rank == ii ) {
// my turn to write to the file
writeStuffToTheFile();
}
MPI_Barrier(MPI_COMM_WORLD);
}
このようにして、2つのプロセスがwriteStuffToTheFile
を同時に呼び出していないことを確認できます。
MPI_Barrier()はあまり使用されませんが、便利です。実際、同期通信を使用している場合でも、MPI_Send/Recv()は2つのプロセスが同期していることのみを確認できます。私のプロジェクトであるcuda + MPIプロジェクトでは、非同期通信のみを使用しています。 MPI_Barrier()に続けてWait()関数を使用しない場合、2つのプロセス(gpu)が同時にデータを相互に送信したいという状況が発生する可能性が非常に高いことがわかりました。プログラムの効率を下げます。上記のバグは私を怒らせ、発見するのに数日かかります。したがって、プログラムでMPI_Isend/Irecvを使用したときにMPI_Barrier()を使用するかどうかを慎重に検討することができます。プロセスを同期する必要があるだけでなく、MUSTの場合もあります。特に、プログラムがデバイスを処理している必要があります。