Synchronization 何时需要使用MPI_Barrier()?

Synchronization 何时需要使用MPI_Barrier()?,synchronization,mpi,openmpi,Synchronization,Mpi,Openmpi,我想知道我什么时候需要使用屏障?例如,我需要在分散/聚集之前/之后使用它吗?或者,OMPI是否应确保所有流程在分散/聚集之前都已达到该点?类似地,在广播之后,我能期望所有进程都已经接收到消息吗 在MPI-3.0之前,MPI中的所有集合操作都是阻塞的,这意味着在它们返回后使用传递给它们的所有缓冲区是安全的。特别是,这意味着所有数据都是在其中一个函数返回时接收到的。(但是,这并不意味着所有数据都已发送!) 因此,如果所有缓冲区都已有效,则在集合操作之前/之后,MPI_屏障是不必要的(或非常有用的)

我想知道我什么时候需要使用屏障?例如,我需要在分散/聚集之前/之后使用它吗?或者,OMPI是否应确保所有流程在分散/聚集之前都已达到该点?类似地,在广播之后,我能期望所有进程都已经接收到消息吗

在MPI-3.0之前,MPI中的所有集合操作都是阻塞的,这意味着在它们返回后使用传递给它们的所有缓冲区是安全的。特别是,这意味着所有数据都是在其中一个函数返回时接收到的。(但是,这并不意味着所有数据都已发送!) 因此,如果所有缓冲区都已有效,则在集合操作之前/之后,MPI_屏障是不必要的(或非常有用的)

还请注意,MPI_屏障不会神奇地等待非阻塞调用。如果使用非阻塞发送/接收,并且两个进程在发送/接收对之后在MPI_屏障处等待,则不能保证进程在MPI_屏障之后发送/接收所有数据。改用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_屏障仅在少数情况下有用。大多数时候,您并不关心进程是否同步。最好阅读有关阻塞和非阻塞呼叫的内容

MPI\u屏障的一种用法是,例如,控制对外部资源(如文件系统)的访问,该文件系统不使用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);
}
int秩、大小;
MPI通信等级(MPI通信世界和等级);
MPI_通信大小(MPI_通信世界和大小);
用于(int ii=0;ii
这样,您就可以确保没有两个进程同时调用
writeStuffToTheFile

可能不经常使用MPI_Barrier(),但它很有用。 事实上,即使使用同步通信,MPI_Send/Recv()也只能确保这两个进程是同步的。 在我的一个cuda+MPI项目中,我使用的只是异步通信。 我发现,在某些情况下,如果不使用MPI_Barrier()和Wait()函数,很可能会出现两个进程(gpu)希望同时相互传输数据的情况,这可能会严重降低程序效率。
上面的虫子让我发疯,我花了几天时间才找到它。因此,在程序中使用MPI Isend/Irecv时,您可能会仔细考虑是否使用MPI Isend()。有时,同步进程不仅是必要的,而且是必须的,尤其是您的程序正在处理设备。

为什么第一个
(!)
是一个错误?进程0仍将有自己的缓冲区?此外,由于它是一个发送,接收方不会对其进行更改,对吗?@JiewMeng MPI不能在调用MPI_Isend后立即从缓冲区读取。如果您在
(!)
更改它,您可能会发送不同的内容。我不太确定,但我认为在这种情况下,行为是未定义的。我稍微更新了您的答案,因为MPI-3.0引入了非阻塞集合。“特别是,这意味着所有数据都是在其中一个函数返回时接收的。(然而,这并不意味着所有数据都已发送!)”-这不一致吗?如何在不发送的情况下接收所有数据?也许您的意思是,因为所有的集体操作都是阻塞的,所以在
send
调用之后,可以安全地将数据与要发送的数据一起重用缓冲区(因为这就是“阻塞”的含义),因为它是由MPI“复制”的(不一定以与缓冲发送
MPI\u Bsend
相同的方式)?当然,当阻止发送返回时,我们不能确定数据是否被接收,这是正确的。@falconepl你是对的,这就是我所说的。在我看来,措辞并没有前后矛盾,但我希望你的评论能让那些和你有同样感受的人更加清楚。非常感谢。再重复一次:阻塞发送并不意味着消息已经发送和接收,只意味着可以重用缓冲区。阻塞接收调用意味着所有数据都已接收。