mpi4py 中的全发散操作

上一篇中我们介绍了 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], 其中 countdispl 都是一个整数系列,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 中的全发散操作方法,下一篇中我们将介绍扫描操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,908评论 6 541
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,324评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,018评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,675评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,417评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,783评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,779评论 3 446
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,960评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,522评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,267评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,471评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,009评论 5 363
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,698评论 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,099评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,386评论 1 294
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,204评论 3 398
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,436评论 2 378

推荐阅读更多精彩内容

  • 在上一篇中我们介绍了 mpi4py 中的全规约操作方法,下面我们将介绍规约发散操作。 对组内通信子上的规约发散操作...
    自可乐阅读 1,262评论 0 0
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,716评论 25 708
  • 前言 计算机编程语言很多,但是适合高性能数值计算的语言却并不多,在高性能计算的项目中通常会使用到的语言有 Fort...
    自可乐阅读 19,837评论 3 22
  • 你塞满我整个过去,却在我的未来永远地缺席。 肖小叉 【1】 都...
    肖小叉阅读 424评论 2 4
  • 公婆呆在老家建房子,向来养尊处优的娃,从这个学期开始,要去托管中心,学会独立自主了。 娃相中邻居家开的托管中心,他...
    Wendy徐阅读 730评论 6 4