mpi4py 中的属性和命名操作

在上一篇中我们介绍了 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 为所创建的属性键,vk 所关联的值,可以在这两个函数中定制对某个值的复制和删除行为,然后将它们作为参数传递给 copy_fndelete_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 中的错误处理。

你可能感兴趣的:(mpi4py 中的属性和命名操作)