加入的Python进程不会调用atexit

时间:2014-10-19 16:32:04

标签: python multiprocessing atexit

我认为Python Processes在终止时会调用它们的atexit函数。请注意,我使用的是Python 2.7。这是一个简单的例子:

from __future__ import print_function
import atexit
from multiprocessing import Process


def test():
    atexit.register(lambda: print("atexit function ran"))

process = Process(target=test)
process.start()
process.join()

我希望这会打印“atexit function ran”,但事实并非如此。

请注意这个问题: Python process won't call atexit 类似,但它涉及以信号终止的进程,答案涉及拦截该信号。这个问题中的进程正在优雅地退出,所以(据我所知,无论如何)这个问题&答案不适用(除非这些进程因某种方式的信号而退出?)。

1 个答案:

答案 0 :(得分:3)

我通过研究如何在CPython中实现它来做了一些研究。假设您在Unix上运行。如果您在Windows上运行,则以下可能无效,因为multiprocessing中的流程实现不同。

事实证明,os._exit()始终在流程结束时被调用。这与atexit文档中的以下注释一起,可以解释为什么你的lambda没有运行。

  

注意:当通过此模块注册的功能时不会被调用   当一个Python时,程序被Python处理的信号杀死   检测到致命的内部错误,或者调用os._exit()时。


这里是CPython 2.7的Popen类的摘录,用于分叉过程。请注意,分叉进程的最后一个语句是对os._exit()的调用。

# Lib/multiprocessing/forking.py

class Popen(object):

    def __init__(self, process_obj):
        sys.stdout.flush()
        sys.stderr.flush()
        self.returncode = None

        self.pid = os.fork()
        if self.pid == 0:
            if 'random' in sys.modules:
                import random
                random.seed()
            code = process_obj._bootstrap()
            sys.stdout.flush()
            sys.stderr.flush()
            os._exit(code)

在Python 3.4中,如果您正在启动分叉过程,os._exit()仍然存在,这是默认值。但似乎您可以更改它,有关详细信息,请参阅Contexts and start methods。我还没有尝试过,但也许使用 spawn 的启动方法会有效吗?但不适用于Python 2.7。