在上一篇中我们介绍了 MPI 3.1 新增的若干功能,下面我们将介绍 mpi4py 中的属性和命名操作。
应用程序可在运行时定制一些信息与相应的 MPI 对象(包括通信子对象,数据类型对象,窗口对象等)相关联,称之为该对象的属性。实际上,MPI 内部的一些工作机制也是通过这种方式来实现的,如集合操作,虚拟进程拓扑等。属性为本地(当前)进程和相关对象所私有,不会自动迁移到其它对象中,除非使用像 MPI_Comm_dup 等的操作进行复制。
从 MPI-2 开始也可对 MPI 对象命名。命名 MPI 对象可方便错误处理、调试等工作。命名 MPI 对象无须全局同步,即命名函数是一个本地操作。 MPI 对象命名后不会因复制而被其副本继承。对象的名字采用与属性不同的处理方式——即对象的名字由 MPI 环境复制保存而非通过应用程序加以维护。
下面对属性和命名操作的相关方法接口进行介绍。
通信子
MPI.Comm.Create_keyval(type cls, copy_fn=None, delete_fn=None, nopython=False)
创建并返回一个与通信子对象关联的属性键(为一个整型值),以后使用该键访问其所关联的值。copy_fn
为属性复制函数,用于定义在调用 MPI.Comm.Dup 时复制相应属性的策略,delete_fn
为属性删除函数,用于定义在调用 MPI.Comm.Free 或 MPI.Comm.Delete_attr 时释放相应属性的策略。当 copy_fn
为 None 时,会使用默认的复制函数(默认行为为不复制),当 delete_fn
为 None 时,会使用默认的删除函数(默认行为为不删除),如果非 None,它们的函数原型定义为
def copy_fn(o, k, v):
和
def del_fn(o, k, v):
其中的参数为:o
为属性所关联的对象,k
为所创建的属性键,v
为 k
所关联的值,可以在这两个函数中定制对某个值的复制和删除行为,然后将它们作为参数传递给 copy_fn
和 delete_fn
以实现特定的复制和删除行为。参数 nopython
指明是否可以设置 Python 对象作为属性,其默认值 False 表明可以设置 Python 对象作为属性,否则只能设置 C/Fortran 支持的数据对象。
MPI.Comm.Free_keyval(type cls, int keyval)
将属性键 keyval
的值设置为 MPI.KEYVAL_INVALID 并返回,待不用时释放占用空间。
MPI.Comm.Set_attr(self, int keyval, attrval)
为属性键 keyval
设置属性值 attrval
,如果指定的 keyval
键尚不存在则出错,如果该键已经有属性值,则该调用相当于先调用 MPI.Comm.Delete_attr 删除旧值,然后再设置新值。注意:当调用 MPI.Comm.Create_keyval 创建 keyval
时如果其 nopython
参数为 False,则此处 attrval
可以为 Python 对象如列表,字典等,但是如果 nopython
参数为 True,则此处 attrval
只能是C/Fortran 支持的数据对象。
MPI.Comm.Get_attr(self, int keyval)
获取并返回属性键 keyval
的值。如果指定的 keyval
键尚不存在则出错,如果存在但没有设置属性值,则返回 None。
MPI.Comm.Delete_attr(self, int keyval)
删除属性键 keyval
的值。该方法将自动调用创建属性键(调用 MPI.Comm.Create_keyval)时设置的删除函数,如果删除函数返回错误,则本次调用也会相应地返回错误。
MPI.Comm.Set_name(self, name)
为当前通信子对象设置名字为 name
。名字字符串 name
中,前面的空格有效,后面的空格忽略。名字长度由 MPI.MAX_OBJECT_NAME 定义。MPI 默认定义的 2 个通信子 MPI.COMM_WORLD 和 MPI.COMM_SELF 分别预定义了各自的名字,但用户可通过调用该方法覆盖预定义的名字。
MPI.Comm.Get_name(self)
读取并返回当前通信子对象的名字。
数据类型
同 MPI.Comm 的对应方法,不过对象为数据类型 MPI.Datatype。
MPI.Datatype.Create_keyval(type cls, copy_fn=None, delete_fn=None, nopython=False)
MPI.Datatype.Delete_attr(self, int keyval)
MPI.Datatype.Free_keyval(type cls, int keyval)
MPI.Datatype.Get_attr(self, int keyval)
MPI.Datatype.Set_attr(self, int keyval, attrval)
MPI.Datatype.Set_name(self, name)
MPI.Datatype.Get_name(self)
窗口
同 MPI.Comm 的对应方法,不过对象为窗口 MPI.Win。
MPI.Win.Create_keyval(type cls, copy_fn=None, delete_fn=None, nopython=False)
MPI.Win.Delete_attr(self, int keyval)
MPI.Win.Free_keyval(type cls, int keyval)
MPI.Win.Get_attr(self, int keyval)
MPI.Win.Get_name(self)
MPI.Win.Set_attr(self, int keyval, attrval)
MPI.Win.Set_name(self, name)
例程
下面给出使用例程。
# attrs.py
"""
Demonstrates the usage of attribute and name operations.
Run this with 1 processes like:
$ mpiexec -n 1 python attrs.py
or
$ python attrs.py
"""
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD
win = MPI.Win.Create(MPI.BOTTOM, 1, MPI.INFO_NULL, comm)
dtype = MPI.INT
def copy_fn(o, k, v):
print 'inside copy_fn: o = %s, k = %s, v = %s' % (o, k, v)
return v
def del_fn(o, k, v):
print 'inside delete_fn: o = %s, k = %s, v = %s' % (o, k, v)
for cls, cls_name, obj, obj_name in [ (MPI.Comm, 'MPI.Comm', comm, 'MPI.COMM_WORLD'),
(MPI.Datatype, 'MPI.Datatype', dtype, 'MPI.INT'),
(MPI.Win, 'MPI.Win', win, 'win') ]:
# use the default copy_fn and delete_fn
keyval = cls.Create_keyval()
attr = obj.Get_attr(keyval)
print 'before Set_attr of %s: attr = %s' % (obj_name, attr)
# can set attr as a Python list only if nopython is False (the default)
obj.Set_attr(keyval, [1, 2, 3])
attr = obj.Get_attr(keyval)
print 'after Set_attr of %s: attr = %s' % (obj_name, attr)
obj.Delete_attr(keyval)
attr = obj.Get_attr(keyval)
print 'after Delete_attr of %s: attr = %s' % (obj_name, attr)
keyval = cls.Free_keyval(keyval)
print 'after Free_keyval of %s keyval == MPI.KEYVAL_INVALID: %s' % (obj_name, keyval == MPI.KEYVAL_INVALID)
# use customed copy_fn and delete_fn, and set nopython = True
keyval = cls.Create_keyval(copy_fn=copy_fn, delete_fn=del_fn, nopython=True)
attr = obj.Get_attr(keyval)
print 'before Set_attr of %s: attr = %s' % (obj_name, attr)
obj.Set_attr(keyval, 123)
attr = obj.Get_attr(keyval)
print 'after Set_attr of %s: attr = %s' % (obj_name, attr)
if hasattr(obj, 'Dup'):
dup = obj.Dup()
attr = dup.Get_attr(keyval)
print 'after Dup of %s: attr = %s' % (obj_name, attr)
obj.Delete_attr(keyval)
attr = obj.Get_attr(keyval)
print 'after Delete_attr of %s: attr = %s' % (obj_name, attr)
keyval = cls.Free_keyval(keyval)
print 'after Free_keyval of %s keyval == MPI.KEYVAL_INVALID: %s' % (obj_name, keyval == MPI.KEYVAL_INVALID)
# name operations
print 'default name of %s: %s' % (obj_name, obj.Get_name())
if cls_name == 'MPI.Comm':
print 'default name of MPI.COMM_SELF: %s' % MPI.COMM_SELF.Get_name()
obj.Set_name('new_name')
print 'name of %s after Set_name: %s' % (obj_name, obj.Get_name())
运行结果如下:
$ python attrs.py
before Set_attr of MPI.COMM_WORLD: attr = None
after Set_attr of MPI.COMM_WORLD: attr = [1, 2, 3]
after Delete_attr of MPI.COMM_WORLD: attr = None
after Free_keyval of MPI.COMM_WORLD keyval == MPI.KEYVAL_INVALID: True
before Set_attr of MPI.COMM_WORLD: attr = None
after Set_attr of MPI.COMM_WORLD: attr = 123
inside copy_fn: o = , k = 12, v = 123
after Dup of MPI.COMM_WORLD: attr = 123
inside delete_fn: o = , k = 12, v = 123
after Delete_attr of MPI.COMM_WORLD: attr = None
after Free_keyval of MPI.COMM_WORLD keyval == MPI.KEYVAL_INVALID: True
default name of MPI.COMM_WORLD: MPI_COMM_WORLD
default name of MPI.COMM_SELF: MPI_COMM_SELF
name of MPI.COMM_WORLD after Set_name: new_name
before Set_attr of MPI.INT: attr = None
after Set_attr of MPI.INT: attr = [1, 2, 3]
after Delete_attr of MPI.INT: attr = None
after Free_keyval of MPI.INT keyval == MPI.KEYVAL_INVALID: True
before Set_attr of MPI.INT: attr = None
after Set_attr of MPI.INT: attr = 123
inside copy_fn: o = , k = 13, v = 123
after Dup of MPI.INT: attr = 123
inside delete_fn: o = , k = 13, v = 123
after Delete_attr of MPI.INT: attr = None
after Free_keyval of MPI.INT keyval == MPI.KEYVAL_INVALID: True
default name of MPI.INT: MPI_INT
name of MPI.INT after Set_name: new_name
before Set_attr of win: attr = None
after Set_attr of win: attr = [1, 2, 3]
after Delete_attr of win: attr = None
after Free_keyval of win keyval == MPI.KEYVAL_INVALID: True
before Set_attr of win: attr = None
after Set_attr of win: attr = 123
inside delete_fn: o = , k = 14, v = 123
after Delete_attr of win: attr = None
after Free_keyval of win keyval == MPI.KEYVAL_INVALID: True
default name of win: rdma window 3
name of win after Set_name: new_name
以上介绍了 mpi4py 中的属性和命名操作,在下一篇中我们将介绍 mpi4py 中的错误处理。