在上一篇中我们对集合通信做了一个非常简要的介绍,后面我们将逐步介绍 mpi4py 中提供的各个集合通信操作方法,下面我们从广播操作开始。
对组内通信子上的广播操作而言, 组内被标记为根的进程向组内所有其它进程发送消息。
对于组间通信子上的广播操作,其作用是以某个组内的某进程为根,向另外组的其它所有进程广播消息。参与广播操作的组间通信子内包含的所有进程都要参与执行 Bcast 函数,根进程所在的组内除根外的所有其它进程的 root
参数应该设置成 MPI.PROC_NULL,根进程的 root
参数使用 MPI.ROOT;另外组的所有进程的 root
参数为根进程在其所处组内的 rank 值。
需要注意的是,对于组间通信子上的广播操作,与根处于同一组的其它进程均不接收广播消息,而远程组的所有进程都可接收到广播消息。与此相对,在组内通信的广播操作中,根进程同样也要参与通信并接收来自其自身的消息。
mpi4py 中的广播操作的方法(MPI.Comm 类的方法)接口为:
bcast(self, obj, int root=0)
Bcast(self, buf, int root=0)
其中以小写字母开头的 bcast 可以广播任意可被 pickle 系列化的 Python 对象 obj
,并返回所接收到的 obj
;以大写字母开头的 Bcast 只能广播具有单段缓冲区接口的类数组对象,如 numpy 数组,参数 buf
可以是一个长度为2或3的 list 或 tuple,类似于 [data, MPI.DOUBLE]
,或者 [data, count, MPI.DOUBLE]
,以指明发送/接收数据缓冲区,数据计数以及数据类型。当 count
省略时会利用 data
的字节长度和数据类型计算出对应的 count
。对 numpy 数组,其计数和数据类型可以自动推断出来,因此可以直接以 data
作为第一个参数传给 buf
。
下面给出广播操作的使用例程。
# intra_comm_bcast.py
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
# broadcast a generic object by using bcast
if rank == 1:
obj = {'a': 1}
else:
obj = None
obj = comm.bcast(obj, root=1)
print 'rank %d has %s' % (rank, obj)
# broadcast a numpy array by using Bcast
if rank == 2:
ary = np.arange(10, dtype='i')
else:
ary = np.empty(10, dtype='i')
comm.Bcast(ary, root=2)
print 'rank %d has %s' % (rank, ary)
运行结果如下:
$ mpiexec -n 3 python intra_comm_bcast.py
rank 1 has {'a': 1}
rank 2 has {'a': 1}
rank 0 has {'a': 1}
rank 1 has [0 1 2 3 4 5 6 7 8 9]
rank 0 has [0 1 2 3 4 5 6 7 8 9]
rank 2 has [0 1 2 3 4 5 6 7 8 9]
# inter_comm_bcast.py
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
if rank == 1:
obj = {'a': 1}
else:
obj = None
# split comm into three new communicators according to `color`
color = rank % 3
comm_split = comm.Split(color=color, key=rank)
# group 0 with color = 0 -> rank = {0, 3, 6}
# group 1 with color = 1 -> rank = {1, 4, 7}
# group 2 with color = 2 -> rank = {2, 5, 8}
# broadcast `obj` from rank 0 of group1 (rank 1 of COMM_WORLD) to all process in group 2
if color == 1:
# create an inter-communicator by using rank 0 of local_comm and rank 2 of MPI.COMM_WORLD
comm_inter = comm_split.Create_intercomm(0, comm, 2, tag=12)
if comm_inter.rank == 0:
root = MPI.ROOT
else:
root = MPI.PROC_NULL
comm_inter.bcast(obj, root=root)
elif color == 2:
# create an inter-communicator by using rank 0 of local_comm and rank 1 of MPI.COMM_WORLD
comm_inter = comm_split.Create_intercomm(0, comm, 1, tag=12)
obj = comm_inter.bcast(obj, root=0)
print 'rank %d has %s...' % (rank, obj)
运行结果如下:
$ mpiexec -n 9 python inter_comm_bcast.py
rank 3 has None
rank 6 has None
rank 0 has None
rank 1 has {'a': 1}
rank 2 has {'a': 1}
rank 4 has None
rank 5 has {'a': 1}
rank 7 has None
rank 8 has {'a': 1}
以上我们介绍了 mpi4py 中的广播操作方法,在下一篇中我们将介绍发散操作。