python mpi4py 读取json_mpi4py 中的全发散操作

本文详细介绍了mpi4py库中的全发散操作方法,包括alltoall、Alltoall、Alltoallv和Alltoallw的用法,以及如何在Python中通过numpy数组和自定义对象进行数据交换。通过示例展示了如何正确设置发送和接收缓冲区,以及数据类型的配置。
摘要由CSDN通过智能技术生成

在上一篇中我们介绍了 mpi4py 中的规约发散操作方法,下面我们将介绍全发散操作。

对组内通信子上的全发散操作,组内所有进程都会执行散发操作,并从所有进程接收数据。

对组间通信子上的全发散操作,假定相关联的组为 group A 和 group B,group A 中的所有进程都会向 group B的各个进程散发消息,同时 group B 的各个进程也会向 group A 的各个进程散发消息。要求 group A 中进程 i 发送缓冲区的第 j 个位置,必须与 group B 中进程 j 接收缓冲区的第 i 个位置匹配;反之亦然。从 group A 到 group B 两个方向上传输的数据可以不对称,甚至在一个方向上传输的数据可以为 0。

方法接口

mpi4py 中的全发散操作的方法(MPI.Comm 类的方法)接口为:

alltoall(self, sendobj)

Alltoall(self, sendbuf, recvbuf)

Alltoallv(self, sendbuf, recvbuf)

Alltoallw(self, sendbuf, recvbuf)

以小写字母开头的 alltoall 可以全发散一系列可被 pickle 系列化的 Python 对象 sendobj。注意:对组内通信子上的该操作,系列长度是组内的进程数 size,而对组间通信子上的该操作,系列长度应是另一组的进程数目,以保证散发的消息可被顺利接收。

以大写字母开头的 Alltoall 只能全发散具有单段缓冲区接口的类数组对象,如 numpy 数组。参数 sendbuf/recvbuf 可以是一个长度为2或3的 list 或 tuple,类似于 [data, MPI.DOUBLE],或者 [data, count, MPI.DOUBLE],以指明发送/接收数据缓冲区,数据计数以及数据类型。当 count 省略时会利用 data 的字节长度和数据类型计算出对应的 count。对 numpy 数组,其计数和数据类型可以自动推断出来,因此可以直接以 data 作为参数传给 sendbuf/recvbuf。

Alltoall 只能散发长度相同的数据量,而 Alltoallv 则可散发不同长度的数据量,为此需要设置发散缓冲区的偏移索引和发送数量数组,以及接收缓冲区的偏移索引和接收数量数组。具体来说,sendbuf/recvbuf 要设置成类似于 [data, count, displ, MPI.DOUBLE], 其中 count 和 displ 都是一个整数系列,count 指明各个进程发送/接收的数据个数,displ 指明各个进程的数据段在发送/接收数据缓冲区中的起始偏离。因为要求进程 i 发送缓冲区的第 j 个位置必须与进程 j 接收缓冲区的第 i 个位置匹配,反之亦然,所以发送缓冲区的计数排列成的矩阵与接收缓冲区的计数排列成的矩阵应该互为转置矩阵。

Alltoallw 是对 Alltoallv 的进一步扩展,不仅可以发送不同长度的数据,还可以发送不同类型的数据,为此,它的参数 send_buf/recv_buf 需要分别指定发送/接收数据缓冲区,通信数据量数组,偏移信息数组和数据类型数组。注意:与 Alltoallv 不同的是,它的发送/接收数据偏移以字节为单位指定。因为要求进程 i 发送缓冲区的第 j 个位置必须与进程 j 接收缓冲区的第 i 个位置匹配,反之亦然,所以发送缓冲区的计数排列成的矩阵与接收缓冲区的计数排列成的矩阵应该互为转置矩阵,同时发送缓冲区的数据类型排列成的矩阵与接收缓冲区的数据类型排列成的矩阵应该互为转置矩阵。

对组内通信子对象的 Alltoall,Alltoallv 和 Alltoallw,可以将其 sendbuf 参数设置成 MPI.IN_PLACE,此时 recvbuf 将既作为发送缓冲区,又作为接收缓冲区。因为要求进程 i 发送缓冲区的第 j 个位置必须与进程 j 接收缓冲区的第 i 个位置匹配,反之亦然,所以缓冲区的计数排列成的矩阵以及数据类型排列成的矩阵都应该是对称的。

例程

下面给出全发散操作的使用例程。

# alltoall.py

"""

Demonstrates the usage of alltoall, Alltoall, Alltoallv, Alltoallw.

Run this with 4 processes like:

$ mpiexec -n 4 python alltoall.py

"""

import numpy as np

from mpi4py import MPI

comm = MPI.COMM_WORLD

rank = comm.Get_rank()

# ------------------------------------------------------------------------------

# alltoall

send_obj = [1.2, 'xy', {'a': 1}, (2,)]

recv_obj = comm.alltoall(send_obj)

print 'alltoall: rank %d has %s' % (rank, recv_obj)

# ------------------------------------------------------------------------------

# Alltoall

send_buf = np.arange(4, dtype='i')

recv_buf = np.empty(4, dtype='i')

comm.Alltoall(send_buf, recv_buf)

print 'Alltoall: rank %d has %s' % (rank, recv_buf)

# ------------------------------------------------------------------------------

# Alltoall with MPI.IN_PLACE

recv_buf = np.arange(4, dtype='i')

comm.Alltoall(MPI.IN_PLACE, recv_buf)

print 'Alltoall with MPI.IN_PLACE: rank %d has %s' % (rank, recv_buf)

# ------------------------------------------------------------------------------

# Alltoallv

send_buf = np.arange(8, dtype='i')

recv_buf = np.empty(8, dtype='i')

if rank == 0:

send_cnt = [2, 3, 1, 2]

send_dpl = [0, 2, 5, 6]

recv_cnt = [2, 3, 2, 1]

recv_dpl = [0, 2, 5, 7]

elif rank == 1:

send_cnt = [3, 2, 2, 1]

send_dpl = [0, 3, 5, 7]

recv_cnt = [3, 2, 1, 2]

recv_dpl = [0, 3, 5, 6]

elif rank == 2:

send_cnt = [2, 1, 3, 2]

send_dpl = [0, 2, 3, 6]

recv_cnt = [1, 2, 3, 2]

recv_dpl = [0, 1, 3, 6]

else:

send_cnt = [1, 2, 2, 3]

send_dpl = [0, 1, 3, 5]

recv_cnt = [2, 1, 2, 3]

recv_dpl = [0, 2, 3, 5]

# the matrix of recv_cnt should be the transpose of the matrix of send_cnt

# [[2, 3, 1, 2], [[2, 3, 2, 1],

# A = [3, 2, 2, 1], B = A.T = [3, 2, 1, 2],

# [2, 1, 3, 2], [1, 2, 3, 2],

# [1, 2, 2, 3]] [2, 1, 2, 3]]

comm.Alltoallv([send_buf, send_cnt, send_dpl, MPI.INT], [recv_buf, recv_cnt, recv_dpl, MPI.INT])

print 'Alltoallv: rank %d has %s' % (rank, recv_buf)

# ------------------------------------------------------------------------------

# Alltoallv with MPI.IN_PLACE

recv_buf = np.arange(8, dtype='i')

if rank == 0:

cnt = [2, 3, 1, 2]

dpl = [0, 2, 5, 6]

elif rank == 1:

cnt = [3, 1, 2, 2]

dpl = [0, 3, 4, 6]

elif rank == 2:

cnt = [1, 2, 2, 3]

dpl = [0, 1, 3, 5]

else:

cnt = [2, 2, 3, 1]

dpl = [0, 2, 4, 6]

# with MPI.IN_PLACE, the maxtrix of cnt should be symmetric

# [[2, 3, 1, 2],

# A = A.T = [3, 1, 2, 2],

# [1, 2, 2, 3],

# [2, 2, 3, 1]]

comm.Alltoallv(MPI.IN_PLACE, [recv_buf, cnt, dpl, MPI.INT])

print 'Alltoallv with MPI.IN_PLACE: rank %d has %s' % (rank, recv_buf)

# ------------------------------------------------------------------------------

# Alltoallw example 1

send_buf = bytearray(b"abcd")

recv_buf = bytearray(4)

cnt = [1, 1, 1, 1]

dpl = [0, 1, 2, 3]

typ = [MPI.CHAR, MPI.CHAR, MPI.CHAR, MPI.CHAR]

comm.Alltoallw([send_buf, cnt, dpl, typ], [recv_buf, cnt, dpl, typ])

# or

# comm.Alltoallw([send_buf, (cnt, dpl), typ], [recv_buf, (cnt, dpl), typ])

print 'Alltoallw1: rank %d has %s' % (rank, recv_buf)

# Alltoallw example 2

# create a send buffer as a numpy structured array with elements with different types

send_buf = np.array([('a', 1, 1.5, 3.2)], dtype=[('a', 'c'), ('b', 'i4'), ('c', 'f4'), ('d', 'f8')])

send_cnt = [1, 1, 1, 1]

send_dpl = [0, 1, 5, 9]

send_typ = [MPI.CHAR, MPI.INT, MPI.FLOAT, MPI.DOUBLE]

if rank == 0:

recv_buf = np.empty(4, dtype='c')

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 1, 2, 3]

recv_typ = [MPI.CHAR, MPI.CHAR, MPI.CHAR, MPI.CHAR]

elif rank == 1:

recv_buf = np.empty(4, dtype='i4')

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 4, 8, 12]

recv_typ = [MPI.INT, MPI.INT, MPI.INT, MPI.INT]

if rank == 2:

recv_buf = np.empty(4, dtype='f4')

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 4, 8, 12]

recv_typ = [MPI.FLOAT, MPI.FLOAT, MPI.FLOAT, MPI.FLOAT]

elif rank == 3:

recv_buf = np.empty(4, dtype='f8')

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 8, 16, 24]

recv_typ = [MPI.DOUBLE, MPI.DOUBLE, MPI.DOUBLE, MPI.DOUBLE]

comm.Alltoallw([send_buf, send_cnt, send_dpl, send_typ], [recv_buf, recv_cnt, recv_dpl, recv_typ])

print 'Alltoallw2: rank %d has %s' % (rank, recv_buf)

# ------------------------------------------------------------------------------

# Alltoallw with MPI.IN_PLACE

if rank == 0:

recv_buf = np.array([('a', 1, 1.5, 3.2)], dtype=[('a', 'c'), ('b', 'i4'), ('c', 'f4'), ('d', 'f8')])

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 1, 5, 9]

recv_typ = [MPI.CHAR, MPI.INT, MPI.FLOAT, MPI.DOUBLE]

if rank == 1:

recv_buf = np.array([(2, 2.5, 4.2, 'b')], dtype=[('b', 'i4'), ('c', 'f4'), ('d', 'f8'), ('a', 'c')])

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 4, 8, 16]

recv_typ = [MPI.INT, MPI.FLOAT, MPI.DOUBLE, MPI.CHAR]

if rank == 2:

recv_buf = np.array([(3.5, 5.2, 'c', 3)], dtype=[('c', 'f4'), ('d', 'f8'), ('a', 'c'), ('b', 'i4')])

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 4, 12, 13]

recv_typ = [MPI.FLOAT, MPI.DOUBLE, MPI.CHAR, MPI.INT]

if rank == 3:

recv_buf = np.array([(6.2, 'd', 4, 4.5)], dtype=[('d', 'f8'), ('a', 'c'), ('b', 'i4'), ('c', 'f4')])

recv_cnt = [1, 1, 1, 1]

recv_dpl = [0, 8, 9, 13]

recv_typ = [MPI.DOUBLE, MPI.CHAR, MPI.INT, MPI.FLOAT]

# with MPI.IN_PLACE, both the maxtrix of cnt and typ should be symmetric

# [[1, 1, 1, 1], [[c, i, f, d],

# A = A.T = [1, 1, 1, 1], B = B.T = [i, f, d, c],

# [1, 1, 1, 1], [f, d, c, i],

# [1, 1, 1, 1]] [d, c, i, f]]

comm.Alltoallw(MPI.IN_PLACE, [recv_buf, recv_cnt, recv_dpl, recv_typ])

print 'Alltoallw with MPI.IN_PLACE: rank %d has %s' % (rank, recv_buf)

运行结果如下:

$ mpiexec -n 4 python alltoall.py

alltoall: rank 0 has [1.2, 1.2, 1.2, 1.2]

alltoall: rank 2 has [{'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}]

alltoall: rank 3 has [(2,), (2,), (2,), (2,)]

alltoall: rank 1 has ['xy', 'xy', 'xy', 'xy']

Alltoall: rank 0 has [0 0 0 0]

Alltoall: rank 2 has [2 2 2 2]

Alltoall: rank 1 has [1 1 1 1]

Alltoall: rank 3 has [3 3 3 3]

Alltoall with MPI.IN_PLACE: rank 0 has [0 0 0 0]

Alltoall with MPI.IN_PLACE: rank 2 has [2 2 2 2]

Alltoall with MPI.IN_PLACE: rank 1 has [1 1 1 1]

Alltoall with MPI.IN_PLACE: rank 3 has [3 3 3 3]

Alltoallv: rank 2 has [5 5 6 3 4 5 3 4]

Alltoallv: rank 0 has [0 1 0 1 2 0 1 0]

Alltoallv: rank 1 has [2 3 4 3 4 2 1 2]

Alltoallv: rank 3 has [6 7 7 6 7 5 6 7]

Alltoallv with MPI.IN_PLACE: rank 2 has [5 4 5 3 4 4 5 6]

Alltoallv with MPI.IN_PLACE: rank 0 has [0 1 0 1 2 0 0 1]

Alltoallv with MPI.IN_PLACE: rank 1 has [2 3 4 3 1 2 2 3]

Alltoallv with MPI.IN_PLACE: rank 3 has [6 7 6 7 5 6 7 7]

Alltoallw1: rank 0 has aaaa

Alltoallw1: rank 1 has bbbb

Alltoallw1: rank 2 has cccc

Alltoallw1: rank 3 has dddd

Alltoallw2: rank 0 has ['a' 'a' 'a' 'a']

Alltoallw2: rank 2 has [ 1.5 1.5 1.5 1.5]

Alltoallw2: rank 1 has [1 1 1 1]

Alltoallw2: rank 3 has [ 3.2 3.2 3.2 3.2]

Alltoallw with MPI.IN_PLACE: rank 1 has [(1, 2.5, 5.2, 'd')]

Alltoallw with MPI.IN_PLACE: rank 2 has [( 1.5, 4.2, 'c', 4)]

Alltoallw with MPI.IN_PLACE: rank 0 has [('a', 2, 3.5, 6.2)]

Alltoallw with MPI.IN_PLACE: rank 3 has [( 3.2, 'b', 3, 4.5)]

以上我们介绍了 mpi4py 中的全发散操作方法,下一篇中我们将介绍扫描操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值