MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm)
此功能不需要rank参数。它如何知道每个过程的等级?
我们应该在广播之前调用MPI_COMM_RANK()
,是否有任何数据结构(如communicator)存储进程的等级?
答案 0 :(得分:5)
也许您认为不可能,但MPI库中的函数可以在内部使用相同的MPI调用来获取进程的级别或通信器的大小。这就是为什么MPI_Bcast()
不需要调用进程的等级,因为它只是调用MPI_Comm_rank()
的内部实现来获取它。以下是来自Open MPI中MPI_Bcast()
实现之一的小样本(更具体地说,这来自tuned
模块中来自coll
框架的拆分二叉树实现,该框架提供了算法实现集体行动):
int
ompi_coll_tuned_bcast_intra_split_bintree ( void* buffer,
int count,
struct ompi_datatype_t* datatype,
int root,
struct ompi_communicator_t* comm,
mca_coll_base_module_t *module,
uint32_t segsize )
{
...
int rank, size;
...
size = ompi_comm_size(comm);
rank = ompi_comm_rank(comm);
...
}
如您所见,它调用了MPI_Comm_size()
和MPI_Comm_rank()
的内部实现。这些是Open MPI中非常便宜的调用。进程的等级存储在与通信器关联的进程组中,并被复制到通信器结构中的一个字段(以保存几个CPU周期,取消引用指向该组的指针)创建沟通者(有关更多信息,请参阅openmpi-source/ompi/communicator/communicator.h
和openmpi-source/ompi/group/group.h
)。
事实上,没有MPI通信原语明确地明确调用进程的等级 - 它总是在内部解决。您只需指定发送数据的位置(例如,在MPI_SEND
中)或从何处接收数据(例如在MPI_RECV
中)或具有一个的集合操作中的数据根。
答案 1 :(得分:2)
考虑MPI_Bcast()
的三种可能实现:
root+1
,然后发送至root+2
,然后发送至root+3
等。这是一个线性数量级N
数据副本的进程都会将数据转发到rank xor 2^N
。这是对数的数量级。在每种情况下,MPI_Bcast()
函数都知道哪个进程将获得下一条消息。在第一种和第三种情况下,任何非root 进程都将只接收数据;在第二个过程中,每个进程一旦收到数据就会继续转发过程。但是,在所有实现中,发送和接收的顺序是确定性的,基于哪个进程是 root 。 (这就是为什么所有进程都必须调用MPI_Bcast()
,无论是否 root 。)
答案 2 :(得分:0)
你是对的,等级存储在通信器中,并且可以在内部实现MPI_Bcast
。在创建通信器时分配等级。例如,MPI_COMM_WORLD
由MPI_Init
创建。
MPI_Comm_rank
只是从通信器获取排名值。在广播之前没有要求呼叫它。但是,了解排名通常是进行任何有意义的编程所必需的。
请注意,由于MPI_Bcast
是一个集体调用,因此需要由通信器中的所有进程执行。
答案 3 :(得分:-1)
int root
,是广播根的等级,基本上MPI广播从等级根发送消息到所有其他等级
在MPI_Init
之后,我也会考虑调用以下内容的“最佳做法” MPI_Comm_rank(MPI_COMM_WORLD, &rank);
这将为每个处理器或核心分配从0到n-1
的int rank值和
MPI_Comm_size( MPI_COMM_WORLD, &Numprocs);
这将创建一个以Numproces为处理器总数的int