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