1

我有以下test_mpi.pypython 脚本:

from mpi4py import MPI
import time

class Foo:
    def __init__(self):
        print('Creation object.')
    def __del__(self):
        print('Object destruction.')

foo = Foo()
time.sleep(10)

如果我在不求助于 mpiexec 的情况下执行它,使用简单的python test_mpi.py5 秒后按 CTRL+C,我会得到以下输出:

ngreiner@Nathans-MacBook-Pro:~/Documents/scratch$ python test_mpi.py 
Creation object.
^CTraceback (most recent call last):
  File "test_mpi.py", line 26, in <module>
    time.sleep(10)
KeyboardInterrupt
Object destruction.
ngreiner@Nathans-MacBook-Pro:~/Documents/scratch$

如果我将它嵌入到 mpiexec 执行中,使用mpiexec -np 1 python test_mpi.py5 秒后再次按 CTRL+C,我现在得到:

ngreiner@Nathans-MacBook-Pro:~/Documents/scratch$ mpiexec -np 1 python test_mpi.py 
Creation object.
^Cngreiner@Nathans-MacBook-Pro:~/Documents/scratch$

来自 python 的回溯和 __del__ 方法的执行已经消失。对我来说主要的问题是不执行 __del__ 方法,它应该在我的实际应用程序中进行一些清理。

知道从 mpiexec 启动 Python 执行时如何执行 __del__ 方法吗?

非常感谢您的帮助,

(我的系统配置:macOS High sierra 10.13.6、Python 3.7.4、open-mpi 4.0.1、mpi4py 3.0.2。)

4

3 回答 3

1

经过一番搜索,我找到了一个解决方案,可以在mpiexec.

在正常的 python 执行期间(不是由 mpiexec 启动,直接从终端启动),点击 ^C 会向 python 发送一个 SIGINT 信号,将其转换为 KeyboardInterrupt 异常(https://docs.python.org/3.7/library/信号.html )。

但是在mpiexec执行过程中点击 ^C 时,它是mpiexec接收 SIGINT 信号的进程,而不是将其传播给其子进程(例如 python),它向其子进程发送一个 SIGTERM 信号(https://www.打开-mpi.org/doc/current/man1/mpirun.1.php)。

因此,python 似乎对 SIGINT 和 SIGTERM 信号的反应不同。

我发现的解决方法是使用信号模块,并为 SIGTERM 信号使用特定的处理程序,这只会引发 KeyboardInterrupt。这可以通过以下几行来实现:

def sigterm_handler():
    raise KeyboardInterrupt

import signal
signal.signal(signal.SIGTERM, sigterm_handler)

前者可以包含在执行的 python 脚本的顶部,或者,为了在每次 pythonmpiexec与 mpi4py 包一起使用时保留此行为,在 mpi4py 包的 __init__.py 文件的顶部。

这种策略可能有副作用(我不知道),使用时应自担风险。

于 2019-09-27T21:22:05.837 回答
0

ngreiner 的回答帮助了我,但至少在 Python 2.7 和所有 Python 3 版本中,处理函数需要两个参数。这个带有虚拟参数的修改代码片段对我有用:

import signal

def sigterm_handler(signum, frame):
    raise KeyboardInterrupt

signal.signal(signal.SIGTERM, sigterm_handler)
于 2020-09-02T13:06:20.827 回答
0

根据文档,不能保证del会被调用。所以你很幸运,它在非 mpi 程序上被调用。

对于简单的情况,您可以使用 try/finally 来确保执行 finally 部分。或者,更一般地说,使用上下文管理器

这是这里重要的文档引用:

不能保证在解释器退出时为仍然存在的对象调用del () 方法。

于 2019-09-26T13:51:39.650 回答