如何在python的多处理子进程中注册"atexit"函数?

ron*_*bai 6 python atexit multiprocess

我有一些子进程(使用多处理),当它们停止时,每个子进程都需要做一些最后的工作.像下面的东西,虽然没有工作......

import multiprocessing
import atexit

def final():
    print "final work"

def worker():
    print 'Doing some work'
    atexit.register(final)

if __name__ == '__main__':
    p = multiprocessing.Process(target=worker)
    p.start()
    p.join()
Run Code Online (Sandbox Code Playgroud)

那怎么能这样呢?

And*_*ini 8

通过多处理启动的进程不会正常退出,atexit函数也不会被调用。您必须通过 try/finally 块手动运行清理内容,例如:

def worker():
    try:
        print('Doing some work')
    finally:
        final()
Run Code Online (Sandbox Code Playgroud)

或者,如果您真的想使用atexit(有关缺点,请参见下文):

def worker():
    try:
        print('Doing some work')
    finally:
        atexit._run_exitfuncs()
Run Code Online (Sandbox Code Playgroud)

为什么子进程不正常退出?

从技术上讲,因为它们通过 退出os._exit(),跳过任何清理工作(包括atexit函数__del__()和弱引用终结器)。

这个决定背后的原因是清理工作有在错误的时间、错误的过程中执行的风险。大多数使用atexit(或其他机制)的代码都希望代码只执行一次,并且仅在主解释器退出时执行(例如,可以atexit用来删除临时目录)。通过在atexit每次子进程退出时执行函数,你打破了这种期望,可能会发生不好的事情。

因此,即使您可以atexit通过运行函数,也要atexit._run_exitfuncs()避免这样做,因为该函数没有记录,而且您可能不是 的唯一用户atexit(其他第三方库可能会使用它,并且您可能会在他们的代码中引入错误)。

  • 这是一个荒谬的决定。atexit 函数不希望从“main”调用。他们希望在他们注册的过程中被调用。所以 atexit 只需要存储注册的 pid 就可以知道它们是否可以被调用。任何使用 atexit 的模块现在都在多处理作业中变得无用......迫使我改用 Popen 并腌制它们自己的状态。我实际上分叉了多处理只是为了重新进行适当的清理。 (7认同)