Fari

python孤儿进程示例和解决方法

子进程原本的父进程停了,它就会由系统的init进程接管,这个子线程就成了孤儿进程,另外还有个僵尸进程的概念,说的是进程已经结束了但是资源没有被父进程清理。

在python中很容易产生孤儿进程,例如以下代码:

import timeimport multiprocessingdef sub_task():    """子进程任务:循环打印时间和父进程状态"""    while True:        print(f"{time.asctime()}, {multiprocessing.parent_process().is_alive()}")        time.sleep(1)def parent_task():    """父进程任务:开启一个循环打印的子进程,然后睡5秒"""    sub_p = multiprocessing.Process(target=sub_task, daemon=True)    sub_p.start()    time.sleep(5) # 将这里的5s修改为2s试试if __name__ == "__main__":    p = multiprocessing.Process(target=parent_task, daemon=False)    p.start()    # 创建“父进程”后主进程睡3秒然后停掉“父进程”    time.sleep(3)    p.terminate()    p.join()    p.close()

上述的代码执行起来就会有问题,你会发现,即使已经将子进程设置为守护进程(daemon=True),将其父进程结束后,该子进程仍然在在打印,但是父进程状态(is_alive())由原来的 True 变为了 False,该进程已经成为了孤儿进程

但是,如果你将上述父进程休眠时间从5秒修改为2秒,则子进程也会随着父进程的退出而退出。

上述代码运行后,通过实验或任务管理器你会发现,父进程确实是在3秒后直接终止了,而子进程却没有。问题就在于父进程是正常退出还是异常退出,当父进程在执行terminate()之前已经执行完了(设置2s的休眠时间),则为正常退出,此时父线程会自动清理其子进程。而如果在执行terminate()的时候父进程仍然在执行(sleep() 设置为5)则为异常退出,此时它还没来得及清理其子进程,故而其子进程成为了孤儿进程

一个比较好的解决方法是使用进程间通信,例如使用 multiprocessing.Event

import timeimport multiprocessingdef sub_task():    """子进程任务:循环打印一个东西"""    while True:        print(f"{time.asctime()}, {multiprocessing.parent_process().is_alive()}")        time.sleep(1)def parent_task(shutdown_flag):    """父进程任务:开启一个循环打印的子进程,然后睡5秒"""    sub_p = multiprocessing.Process(target=sub_task, daemon=True)    sub_p.start()    shutdown_flag.wait()if __name__ == "__main__":    shutdown_flag = multiprocessing.Event()    p = multiprocessing.Process(target=parent_task, args=(shutdown_flag,), daemon=False)    p.start()    # 创建“父进程”后睡3秒然后停掉“父进程”    time.sleep(3)    shutdown_flag.set()    p.join()    p.close()    print("main done")

multiprocessing.Event() 可以理解为一个bool值,有四个方法:

Tags: