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

第二个(非阻止’发送’但阻止’接收’):

 ... 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. 上面给出的3个代码有什么(潜在的)问题(如果有的话)?

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

  3. 这样做的最佳方法是什么(如果不是以上3之一请写出来的话)?

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

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

您的第一个实现可能会导致死锁,特别是如果以同步模式完成通信(可能它在您的测试中有效,因为通信是缓冲的;大数据不太可能)。

其他两个实现应该没有死锁。 我认为在发送之前启动接收操作被认为是更好的做法,所以我个人赞成第3次实现。 根据MPI标准,第3.7节 :

给用户的建议

[…]

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

具有订单MPI_Send / MPI_Send的第三个实现可以在MPI_Send调用中死锁,其原因与第一个实现相同。