MPI发送和接收问题

4

我有关于MPI发送和接收操作的问题。

假设我们有两个尝试相互发送消息的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 );
...

第二种情况(非阻塞的“发送”但是阻塞的“接收”):

...
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);
...

第三种情况(非阻塞的“接收”与阻塞的“发送”):

...
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);
...

我猜以上三个代码可能存在潜在问题,但我想听听您的意见。因此,我有以下问题:
  1. 以上三个代码中有哪些(潜在)问题(如果有)?

  2. 考虑到MPI标准,哪一个是有效/正确的,可以与所有MPI实现一起工作?

  3. 如果以上3种方法都不行,最好的方法是什么?

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

PS:顺便说一句,我已经尝试使用Scali MPI执行它们,它们都可以正常工作!
1个回答

5

你的第一个实现很可能会导致死锁,特别是如果通信是在同步模式下进行的(也许在你的测试中它起作用了,因为通信被缓冲了;但对于大数据来说,这不太可能是情况)。

另外两个实现应该可以避免死锁。我认为在发送之前启动接收操作被认为是更好的实践方式,所以我个人更青睐第三种实现方法。根据MPI标准,第3.7节

用户建议

[...]

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

第三种使用顺序 MPI_Send/MPI_Irecv 的实现可能会在 MPI_Send 调用时出现死锁,原因与第一种实现相同。

我对第二种实现也持怀疑态度,因为我们有一个阻塞接收,它应该会阻塞直到数据被接收。所以,在那种情况下我们不需要使用MPI_Wait()吗? - usman
@user600029 我认为在这种情况下没有死锁的风险,因为两个进程在阻塞接收之前已经启动了它们的发送操作。 - François Févotte
1
@user600029,然而我刚刚意识到,在你的所有实现中,你只分配了一个数据,其地址同时被赋给了发送和接收操作。这样做的结果在第二个和第三个实现中是不可预测的。如果你真的想要交换两个进程中“data”的值,你必须至少在其中一个进程中复制存储(但如果你坚持使用异步通信方案,它不保证通信的顺序,那么最好在两个进程中都复制存储)。 - François Févotte
1
在示例2中,您仍应使用MPI_Wait清理发送请求。或者,您可以使用MPI_Request_free而不是等待。但请记住,在发送完成之前,写入发送缓冲区是不安全的-您可以使用MPI_Wait来检查是否完成发送。 - Greg Inozemtsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接