通常在我们调用MPI_Bcast时,必须确定root。但现在我有一个应用程序,不关心谁将广播该消息。这意味着将广播该消息的节点是随机的,但是一旦广播该消息,全局变量必须是一致的。我的理解是,由于MPI_Bcast是一个集合函数,所有节点都需要调用它,但顺序可能不同。那么谁首先到达MPI_Bcast,谁将把消息广播给其他人。我用3个节点运行以下代码,我想如果节点1(rank == 1)首先到达MPI_Bcast,它会将local_count值(1)发送到其他节点,然后所有节点都使用相同的local_count更新global_count,所以我的预期结果之一是(输出顺序无关紧要)
节点0,全局计数为1
节点1,全局计数为1
节点2,全局计数为1
但实际结果总是(输出顺序无关紧要):
节点1,全局计数为1
节点0,全局计数为0
节点2,全局计数为2
此结果与没有MPI_Bcast的代码完全相同。所以我对MPI_Bcast或我的代码的理解有什么问题。感谢。
#include <mpi.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int rank, size;
int local_count, global_count;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
global_count = 0;
local_count = rank;
MPI_Bcast(&local_count, 1, MPI_INT, rank, MPI_COMM_WORLD);
global_count += local_count;
printf("node %d, global count is: %d\n", rank, global_count);
MPI_Finalize();
}
代码是一个简化的案例。在我的应用程序中,在MPI_Bcast之前有一些计算,我不知道谁将首先完成计算。每当节点到达MPI_Bcast点时,它需要广播自己的计算结果局部变量,并且所有节点都更新全局变量。所以所有节点都需要广播消息,但我们不知道订单。如何实现这个想法?
答案 0 :(得分:2)
MPI_BCast
的正确用法是所有进程都使用相同根调用该函数。即使你不关心广播公司是谁,所有进程都必须调用具有相同等级的功能来收听广播公司。在您的代码中,每个进程都使用自己的排名调用MPI_BCast
,并且彼此不同。
我没有查看标准文档,但很可能通过调用具有不同排名的MPI_BCast
来触发未定义的行为。
答案 1 :(得分:2)
通常你写的会导致死锁。在典型的MPI_Bcast
情况下,具有等级root
的进程将其数据发送到通信器中的所有其他进程。您需要在接收流程中指定相同的root
排名,以便他们知道“倾听”谁。这是一个过于简化的描述,因为通常使用分层广播以减少总操作时间,但是通过三个过程,这种分层实现简化为非常简单的线性实现。在您的案例中,排名为0
的流程会尝试向流程1
和2
发送相同的消息。同时,流程1
将不会收到该消息,而是尝试将其发送到流程0
和2
。流程2
也会尝试发送到0
和1
。最后,每个进程都将发送其他进程不愿意接收的消息。这是一个几乎可以确定的令人沮丧的方法。
为什么你的程序没有挂起?因为发送的消息非常小,所以只有一个MPI_INT
元素和进程数量很小,因此MPI库在每个进程内都会对这些发送进行缓冲 - 它们永远不会到达目的地,但仍然是调用虽然操作仍在进行中,但MPI_Bcast
内部进行的操作不会阻塞,您的代码会返回执行控制。这是未定义的行为,因为MPI库不需要按标准缓冲任何内容 - 某些实现可能缓冲,其他实现可能不缓冲。
如果您尝试计算所有流程中所有local_count
变量的总和,则只需使用MPI_Allreduce
。替换这个:
global_count = 0;
local_count = rank;
MPI_Bcast(&local_count, 1, MPI_INT, rank, MPI_COMM_WORLD);
global_count += local_count;
用这个:
local_count = rank;
MPI_Allreduce(&local_count, &global_count, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
答案 2 :(得分:0)
来自openmpi docs
"MPI_Bcast broadcasts a message from the process with rank root to all processes of the group, itself included. It is called by all members of group using the same arguments for comm, root. On return, the contents of root’s communication buffer has been copied to all processes. "
调用它可能来自排名!= root可能会导致一些问题
更安全的方法是对您自己的广播功能进行硬编码并调用
它基本上是一个for循环和一个mpi_send命令,不应该很难实现你的自我