已连接的Python进程不会调用atexit
我原以为Python进程在结束时会调用它们的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函数运行了”,但实际上并没有。
另外,这个问题:Python进程不会调用atexit也有点类似,但它涉及的是被信号终止的进程,而答案是关于如何拦截那个信号的。这个问题中的进程是正常退出的,所以(就我所知)那个问题和答案并不适用(除非这些进程是因为某种信号而退出的?)。
1 个回答
4
我查了一下在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()
依然存在,这是默认的行为。不过似乎你可以更改这个设置,具体可以查看上下文和启动方法获取更多信息。我还没有尝试过,但也许使用spawn的启动方法会有效?不过在Python 2.7中是不可用的。