假设我有 n 进程,并且每个进程都拥有一个本地数据,比如一个 int 。
现在我想重新实现 MPI_Allreduce() 函数,即计算所有 ints 的全局总和,然后将结果总和广播回进程。
我试着像下面的代码那样做:
int temp;
int my_sum = temp = my_data;
for (int i = 1; i < size; ++i) {
int partner = (my_rank + 1) % size;
MPI_Sendrecv_replace(&temp, 1, MPI_INT,
partner, 0,
my_rank, 0,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
my_sum += temp;
}
以便进程以环形方式进行通信,但它是阻塞的。为什么?如何更改代码以使其正常工作?
注意: 请不要建议该问题的替代(更好)解决方案(显然,其中之一是使用 MPI_Allreduce() 函数)。我的目标是理解为什么这个代码片段不像我认为的那样工作。
最佳答案
每个人都试图从自己那里接收,但他们正在发送到 partner
;由于 partner
永远不会收到正在发送的消息,并且 my_rank
永远不会从它自己那里得到消息,所以会挂起。
如果您尝试向 parter
发送数据,那么您需要确保 partner
正在从您那里接收,这意味着每个人都需要从 (myrank - 1 + size) % size
接收:
int spartner = (my_rank + 1) % size;
int rpartner = (my_rank - 1 + size) % size;
MPI_Sendrecv_replace(&temp, 1, MPI_INT,
spartner, i,
rpartner, i,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
这样,等级 3(比如说)发送到 4,等级 4 在每次迭代时从等级 3 接收,因此 sendrecv 完成。 (我还冒昧地为循环中的每次迭代提供了自己的标签,这在这里并不是真正必要的,但如果存在其他不匹配的消息类型错误,通常有助于找到错误。)