为什么守护程序没有join()就退出

Cla*_*ied 5 python daemon multiprocessing python-2.7 python-3.x

答案可能就在我面前的链接上,但我仍然不明白.我确定在有人向我解释之后,达尔文会打电话给我.

这个例子就在这里,尽管我做了一些改变,试图尝试并帮助我理解.

这是代码:

import multiprocessing
import time
import sys

def daemon():
    p = multiprocessing.current_process()
    print 'Starting: ', p.name, p.pid
    sys.stdout.flush()
    time.sleep(2)
    print 'Exiting: ', p.name, p.pid
    sys.stdout.flush()

def non_daemon():
    p = multiprocessing.current_process()
    print 'Starting: ', p.name, p.pid
    sys.stdout.flush()
    time.sleep(6)
    print 'Exiting: ', p.name, p.pid
    sys.stdout.flush()

if __name__ == '__main__':
    d = multiprocessing.Process(name='daemon', target=daemon)
    d.daemon = True

    n = multiprocessing.Process(name='non-daemon', target=non_daemon)
    n.daemon = False

    d.start()
    time.sleep(1)
    n.start()
#    d.join()
Run Code Online (Sandbox Code Playgroud)

并且代码的输出是:

Starting:  daemon 6173
Starting:  non-daemon 6174
Exiting:  non-daemon 6174
Run Code Online (Sandbox Code Playgroud)

如果取消注释末尾的join(),则输出为:

Starting:  daemon 6247
Starting:  non-daemon 6248
Exiting:  daemon 6247
Exiting:  non-daemon 6248
Run Code Online (Sandbox Code Playgroud)

我很困惑b/c守护进程的睡眠是2秒,而非守护进程是6秒.为什么不在第一种情况下打印出"退出"消息?守护进程应该在非守护进程之前唤醒并打印消息.

该网站的解释如下:

输出不包括来自守护进程的"退出"消息,因为所有非守护进程(包括主程序)在守护程序进程从其2秒睡眠中唤醒之前退出.

但我改变了它,以至于守护进程应该在非守护进程之前唤醒.我在这里错过了什么?在此先感谢您的帮助.

编辑:忘了提到我正在使用python 2.7但显然这个问题也在python 3.x中

Sha*_*ger 6

追踪这一点很有趣。这些文档有些误导,因为它们描述的非守护进程就好像它们都是等效的;任何非守护进程的存在都意味着该进程“家族”还活着。但它的实施方式并非如此。父进程比其他进程“更平等”;multiprocessing注册一个atexit执行以下操作的处理程序:

for p in active_children():
    if p.daemon:
        info('calling terminate() for daemon %s', p.name)
        p._popen.terminate()

for p in active_children():
    info('calling join() for process %s', p.name)
    p.join()
Run Code Online (Sandbox Code Playgroud)

因此,当主进程完成时,它首先 terminate关闭所有daemon子进程,然后 join让所有子进程等待非子daemon进程并清理daemon子进程的资源。

因为它按照这个顺序执行清理,所以在你的 non- 后不久daemon Process start,主进程开始清理并强制terminates daemon Process

请注意,修复此问题可以像手动joining 非daemon进程一样简单,而不仅仅是joiningdaemon进程(这完全破坏了 a 的全部意义daemon);这会阻止atexit处理程序被调用,从而延迟子进程的清理terminate工作daemon

这可以说是一个错误(这个错误似乎一直存在到 3.5.1;我自己重复了一遍),但它是行为错误还是文档错误是有争议的。

  • 我认为这构成了一个错误,因为该行为不同于“线程”(“多处理”应该使用进程而不是线程来模拟),其中守护线程保持运行,而任何非守护线程保持活动状态(主线程或其他线程) 。打开[bug #26633](https://bugs.python.org/issue26633)。 (3认同)