Python 多处理守护进程与非守护进程与主进程

Python multiprocessing daemon vs non-daemon vs main

我在 Python 中学习多处理,同时我发现守护进程和非守护进程之间相对于主进程的这种奇怪行为。 我的代码:

import multiprocessing
import time

def worker(name,num):
    print name, 'Starting'
    time.sleep(num)
    print name, 'Exiting'

if __name__ == '__main__':
    print 'main starting'
    p1=multiprocessing.Process(target=worker, args=("p1",7,))
    p2=multiprocessing.Process(target=worker, args=("p2",5,))
    p2.daemon=True
    p1.start()
    p2.start()
    time.sleep(4)
    print 'main exiting'

我得到的输出是:

main starting
p1 Starting
p2 Starting
main exiting
p1 Exiting

预期输出:

main starting
p1 Starting
p2 Starting
main exiting
p2 Exiting
p1 Exiting

经过几次搜索,我找到了 this answer 并将以下行插入到我的代码中。

logger = multiprocessing.log_to_stderr(logging.INFO)

我得到的输出是,

main starting
[INFO/p1] child process calling self.run()
p1 Starting
[INFO/p2] child process calling self.run()
p2 Starting
main exiting
[INFO/MainProcess] process shutting down
[INFO/MainProcess] calling terminate() for daemon p2
[INFO/MainProcess] calling join() for process p2
[INFO/MainProcess] calling join() for process p1
p1 Exiting
[INFO/p1] process shutting down
[INFO/p1] process exiting with exitcode 0

据我了解,

但是在这里,为什么主进程试图在 p1 退出之前关闭?

以上不是上述程序的正常时间表吗?

任何人都可以解释这里发生了什么以及为什么吗?

编辑

在代码末尾添加行 p1.join() 后,我得到以下输出:

main starting
[INFO/Process-1] child process calling self.run()
p1 Starting
[INFO/Process-2] child process calling self.run()
p2 Starting
main exiting
p2 Exiting
[INFO/Process-2] process shutting down
[INFO/Process-2] process exiting with exitcode 0
p1 Exiting
[INFO/Process-1] process shutting down
[INFO/Process-1] process exiting with exitcode 0
[INFO/MainProcess] process shutting down

当你看到

[INFO/MainProcess] calling join() for process p1

表示主进程还没有退出--在关机的过程中,当然要到join才关机returns...只有在加入过程完成后才会发生。

所以时间线确实如你所料——但由于 joinp1main 过程的最后一个想法,你不知道在输出或日志中看不到它。 (main 已采取所有终止触发的操作,但作为一个进程,它在此之前仍然存在)。

要验证,请使用(在 Unixy 系统上)来自另一个终端的 ps 而 运行 这个(可能会有稍长的延迟来帮助您检查):你永远不会看到一个 Python 从这个复合体中处理 运行 -- 将有两个(main 和 p1)直到结束。

Python 多进程|守护进程和加入

问题最终增加了对守护进程标志和连接方法行为的等待,因此这里用一个简单的脚本进行快速解释。

  1. 守护进程在主程序退出之前自动终止,以避免留下孤立进程 运行ning 但不会随主程序一起终止。所以 守护函数留下的任何未完成的进程都不会 运行!
  2. 但是,如果在守护函数上调用 join() 方法,则主程序 将等待剩余的进程。

输入

        import multiprocessing
        import time
        import logging


        def daemon():
            p = multiprocessing.current_process()
            print('Starting:', p.name, p.pid, flush=True)
            print('---' * 15)
            time.sleep(2)
            print('===' * 15 + ' < ' + f'Exiting={p.name, p.pid}' + ' > ' + '===' * 15, flush=True)



        def non_daemon():
            p = multiprocessing.current_process()
            print('Starting:', p.name, p.pid, flush=True)
            print('---'*15)
            print('===' * 15 + ' < ' + f'Exiting={p.name, p.pid}' + ' > ' + '===' * 15, flush=True)


        if __name__ == '__main__':
            print('==='*15 + ' < ' + 'MAIN PROCESS' + ' > ' + '==='*15)
            logger = multiprocessing.log_to_stderr(logging.INFO)
            # DAEMON
            daemon_proc = multiprocessing.Process(name='MyDaemon', target=daemon)
            daemon_proc.daemon = True

            # NO-DAEMON
            normal_proc = multiprocessing.Process(name='non-daemon', target=non_daemon)
            normal_proc.daemon = False

            daemon_proc.start()
            time.sleep(2)
            normal_proc.start()

            # daemon_proc.join()

输出无连接方法##

============================================= < MAIN PROCESS > =============================================
Starting: MyDaemon 8448
---------------------------------------------
[INFO/MyDaemon] child process calling self.run()
[INFO/MainProcess] process shutting down
[INFO/MainProcess] calling terminate() for daemon MyDaemon
[INFO/MainProcess] calling join() for process MyDaemon
[INFO/MainProcess] calling join() for process non-daemon
Starting: non-daemon 6688
---------------------------------------------
============================================= < Exiting=('non-daemon', 6688) > =============================================
[INFO/non-daemon] child process calling self.run()
[INFO/non-daemon] process shutting down
[INFO/non-daemon] process exiting with exitcode 0

Process finished with exit code 0

函数 daemon() 是 'spleeping' 2 秒,因此当 Python 到达脚本底部时,程序关闭但不是 daemon()。

  • 注:

[INFO/MainProcess] calling terminate() for daemon MyDaemon

现在如果脚本的最后一行 daemon_proc.join() 没有注释。


输出 + 连接方法

============================================= < MAIN PROCESS > =============================================
Starting: MyDaemon 13588
---------------------------------------------
[INFO/MyDaemon] child process calling self.run()
============================================= < Exiting=('MyDaemon', 13588) > =============================================
[INFO/MyDaemon] process shutting down
[INFO/MyDaemon] process exiting with exitcode 0
[INFO/MainProcess] process shutting down
[INFO/MainProcess] calling join() for process non-daemon
Starting: non-daemon 13608
---------------------------------------------
============================================= < Exiting=('non-daemon', 13608) > =============================================
[INFO/non-daemon] child process calling self.run()
[INFO/non-daemon] process shutting down
[INFO/non-daemon] process exiting with exitcode 0

Process finished with exit code 0