MPI_Send() 和 MPI_Isend() 后跟 MPI_Wait() 有什么区别?

What is the difference between MPI_Send() and MPI_Isend() followed by MPI_Wait()?

我无法理解 MPI_Send()MPI_Isend() 后跟 MPI_Wait() 之间的区别。

当我们在 MPI_Isend() 之后使用 MPI_Wait() 时,我们不是在将其变成阻塞调用吗?因为我们必须等到所有元素都复制到缓冲区中。

我知道这个配置(下面给出)可能会导致死锁

  P1--> MPI_Send() MPI_Recv()             
  P2--> MPI_Send() MPI_Recv()

但是这个配置(下面给出)也会导致死锁吗?

 P1--> MPI_Isend() MPI_Wait() MPI_Recv()             
 P2--> MPI_Isend() MPI_Wait() MPI_Recv()

当您使用 MPI_Isend + MPI_Wait 时,您可以将通信与计算重叠:

MPI_Isend(...) // Non blocking send

// Perform computation here (make sure you don't use the buffer you're sending!)

MPI_Wait(...)

上面,当您的数据被发送给收件人时,下面的代码 MPI_Isend 将执行(因为 MPI_Isend 是非阻塞的)。这允许您在进行通信时进行计算。与此不同,MPI_Send() 是不同的,因为它是阻塞的,因此您不能在通信发生时执行计算,就像上面的代码使用 MPI_Isend 后跟 MPI_Wait.

TL;DR: 您需要使用MPI_Wait(或使用MPI_Test来测试请求是否完成)以确保消息已完成,send/receive 缓冲区中的数据可以再次安全 操作。

更详细的回答:

MPI_Isend

Begins a nonblocking send

int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request)

让我们想象一下,您使用 MPI_Isend 发送一个 int 的数组而不调用 MPI_Wait;在这种情况下,您不确定何时可以 安全地 修改(或释放该数组的内存)。 MPI_Irecv也是如此。尽管如此,调用 MPI_Wait 可确保从那一点开始 read/write (或释放内存)缓冲区没有 undefined behavior 或不一致数据的风险。

MPI_Isend期间缓冲区的内容(例如,ints的数组)必须被读取和发送;同样,在 MPI_Irecv 期间,接收缓冲区的内容必须到达。同时,可以将一些计算与正在进行的过程重叠,但是此计算无法更改(或读取)send/recv 缓冲区 的内容。然后调用 MPI_Wait 以确保从那时起数据 send/recv 可以安全地 read/modified 没有任何问题。

I am not able to understand the difference between MPI_Send() and MPI_Isend() followed by MPI_Wait().

从这个SO Thread可以读到:

These functions do not return (i.e., they block) until the communication is finished. Simplifying somewhat, this means that the buffer passed to MPI_Send() can be reused, either because MPI saved it somewhere, or because it has been received by the destination.

最后:

I know that this configuration(given below) may lead to a deadlock

P1--> MPI_Send() MPI_Recv()
P2--> MPI_Send() MPI_Recv()

But can this configuration(given below) also lead to deadlock?

P1--> MPI_Isend() MPI_Wait() MPI_Recv()
P2--> MPI_Isend() MPI_Wait() MPI_Recv()

如果消息交换仅发生在进程 P1P2 之间,那么可以。 语义上 调用 MPI_Isend() 然后调用 MPI_Wait() 与调用 MPI_Send().

相同

P1P2 发送消息并等待该消息完成,但是 P2P1 发送消息并等待。因为,每个进程都在等待对方,这会导致死锁。