Python多处理守护程序与非守护程序vs main

时间:2015-02-20 04:56:12

标签: python multiprocessing

我正在学习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开始睡眠7秒钟。
  • p2开始睡眠5秒钟。
  • 主进程休眠4秒钟。
  • 主进程在4秒后唤醒并等待p1退出。
  • p2在5秒后醒来并退出。
  • p1在7秒后醒来并退出。
  • 主要流程退出。

对于上述程序,上述不是正常的时间线吗?

有人可以解释一下这里发生了什么,为什么?

修改

在代码末尾添加行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

2 个答案:

答案 0 :(得分:1)

当你看到

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

这意味着主要流程还没有退出 - 它在流程关闭,但当然不会关闭,直到join返回...只有在联合过程完成后才会发生。

所以时间轴确实如你所料 - 但由于joinp1是最后一次认为main进程所做的,所以你看不到在输出中或从中记录。 (主要采取了所有终止触发的行动,但作为一个过程,它一直存在直到那时)。

要验证,在运行此程序时使用(在Unixy系统上)ps来自另一个终端(可能会有稍长的延迟来帮助您检查):您永远不会看到单个Python进程耗尽此复杂性 - - 直到结束时会有两个(主要和p1)。

答案 1 :(得分:0)

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

问题最终为守护程序标志和join方法的行为增加了更多等待时间,因此这里将通过一个简单的脚本进行快速解释。

  1. 守护程序进程将在主程序退出之前自动终止,以避免使孤立进程继续运行,但不会被主程序终止。因此,守护程序函数留下的任何未完成的进程将无法运行!
  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()函数将“耗时” 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