MPI 发送和接收问题

usm*_*man 4 c mpi

我对 MPI 发送和接收操作有疑问。

假设我们有 2 个 MPI 线程尝试互相发送消息。以下是执行此操作的三个代码片段:

首先(阻止“发送”和“接收”):

...
int data = ...;
...
MPI_Send( &data, sizeof( int ), MPI_INT, 
        (my_id == 0)?1:0, 0, MPI_COMM_WORLD );

MPI_Status status; 
MPI_Recv( &data, sizeof( int ), MPI_INT,
        (my_id == 0)?1:0, 0, MPI_COMM_WORLD, &status );
...
Run Code Online (Sandbox Code Playgroud)

第二(非阻塞“发送”但阻塞“接收”):

...
int data = ...;
...
MPI_Request request;
MPI_Isend( &data, sizeof( int ), MPI_INT, 
        (my_id == 0)?1:0, 0, MPI_COMM_WORLD, &request);

MPI_Status status; 
MPI_Recv( &data, sizeof( int ), MPI_INT,
        (my_id == 0)?1:0, 0, MPI_COMM_WORLD, &status );
// Synchronize sender & receiver
MPI_Wait( &request, &status);
...
Run Code Online (Sandbox Code Playgroud)

第三种(非阻塞“接收”和阻塞“发送”):

...
int data = ...;
...
MPI_Request request;
MPI_Irecv( &data, sizeof( int ), MPI_INT,
        (my_id == 0)?1:0, 0, MPI_COMM_WORLD, &request );

MPI_Send( &data, sizeof( int ), MPI_INT, 
        (my_id == 0)?1:0, 0, MPI_COMM_WORLD);

MPI_Status status; 

// Synchronize sender & receiver
MPI_Wait( &request, &status);
...
Run Code Online (Sandbox Code Playgroud)

我猜以上三个代码存在潜在问题,但我想听听您的意见。所以,我有以下问题:

  1. 上面给出的 3 个代码有哪些(潜在)问题(如果有)?

  2. 考虑到 MPI 标准,上述三个代码中哪一个是有效/正确的,以便它可以与所有 MPI 实现一起使用?

  3. 最好的方法是什么(如果不是以上 3 种之一,请写下来)?

  4. 在第三个代码中,如果我们更改 MPI_Irecv 和 MPI_Send 调用的顺序会怎样?

PS:顺便说一句,我尝试使用 Scali MPI 执行它们,并且所有这些都有效!

ffe*_*tte 5

您的第一个实现可能会导致死锁,特别是如果通信是在同步模式下完成的(也许它在您的测试中有效,因为通信被缓冲;对于大数据来说不太可能出现这种情况)。

其他两个实现应该不会出现死锁。我相信在发送之前启动接收操作被认为是更好的做法,因此我个人倾向于第三种实现。来自MPI 标准,第 3.7 节

给用户的建议

[...]

消息传递模型意味着通信是由发送者发起的。如果发送方发起通信时已发送接收(数据可以直接移动到接收缓冲区,并且无需对挂起的发送请求进行排队),则通信通常会具有较低的开销。但是,只有在匹配的发送发生后,接收操作才能完成。使用非阻塞接收可以实现较低的通信开销,而无需在等待发送时阻塞接收方。

MPI_Send使用 order /的第三个实现MPI_Irecv可能会在调用中出现死锁MPI_Send,原因与第一个实现相同。