我对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);
...
我猜以上三个代码存在潜在问题,但我想要你的意见。所以,我有以下问题:
上面给出了3个代码的(潜在)问题(如果有的话)是什么?
考虑到MPI标准,上述三个代码中哪一个有效/正确,以便它可以与所有MPI实现一起使用?
这样做的最佳方法是什么(如果不是以上3个中的一个请写出来)?
在第三段代码中,如果我们更改MPI_Irecv和MPI_Send调用的顺序怎么办?
PS:顺便说一句,我尝试使用Scali MPI执行它们并且所有这些都有效!
答案 0 :(得分:4)
你的第一个实现可能会导致死锁,特别是如果在同步模式下完成通信(可能它在你的测试中有效,因为通信是缓冲的;对于大数据来说不太可能)。
其他两个实现应该没有死锁。我认为在发送之前启动接收操作被认为是更好的做法,所以我个人赞成第3次实现。来自MPI standard, section 3.7:
对用户的建议
[...]
消息传递模型意味着通信由发送方发起。如果在发送方启动通信时已经发布了接收,则通信通常具有较低的开销(数据可以直接移动到接收缓冲区,并且不需要对待处理的发送请求进行排队)。但是,只有在匹配发送发生后才能完成接收操作。使用非阻塞接收允许在不等待接收器等待发送的情况下实现较低的通信开销。
订单MPI_Send
/ MPI_Irecv
的第三个实施可能会在MPI_Send
调用中出现与第一个实现相同的原因。