Python多处理和子进程的独立性
Posted
技术标签:
【中文标题】Python多处理和子进程的独立性【英文标题】:Python multiprocessing and independence of children processes 【发布时间】:2014-03-07 02:00:47 【问题描述】:从 python 终端,我运行如下命令,生成一个长时间运行的子进程:
from multiprocessing.process import Process
Process(target=LONG_RUNNING_FUNCTION).start()
此命令返回,我可以在 python 终端中执行其他操作,但孩子打印的任何内容仍会打印到我的 python 终端会话中。
当我退出终端(使用exit
或 CTRL+D)时,退出命令会挂起。如果我在此挂起期间按 CTRL+C,则子进程将终止。
如果我手动终止 python 终端进程(通过 posix kill
命令),子进程将变成孤立的,并继续运行,其输出可能被丢弃。
如果我使用python -c
运行此代码,它会等待子进程终止,并且 CTRL+C 会杀死父进程和子进程。
当父母终止时,python 的哪些运行配置会杀死孩子?特别是,如果 python-mod_wsgi-apache 网络服务器产生子进程然后重新启动,这些子进程会被杀死吗?
[顺便说一句,分离从终端产生的子进程的正确方法是什么?有没有比以下更优雅的方法:Deliberately make an orphan process in python]
更新:由在 apache 下运行的 Web 服务器使用multiprocessing.Process
生成的 python 子进程在 apache 重新启动时不会被杀死。
【问题讨论】:
【参考方案1】:这与你如何调用 python 无关;这是multiprocessing
模块的一个功能。当您导入该模块时,将向父进程添加一个退出处理程序,该处理程序在允许父进程退出之前对通过multiprocessing.Process
创建的所有子进程的Process
对象调用join()
。如果您打算以这种方式启动子进程,那么在不破解模块内部的情况下,就无法避免给您带来麻烦的行为。
如果您想启动一个能够比父进程寿命更长的进程,那么使用subprocess.Popen
可能会为您提供更好的服务。如果孩子以这种方式开始,则父母在退出之前不会尝试加入孩子,而是会立即退出,留下一个孤儿:
>>> from subprocess import Popen
>>> Popen(["sleep", "100"])
<subprocess.Popen object at 0x10d3fedd0>
>>> exit()
alp:~ $ ps -opid,ppid,command | grep sleep | grep -v grep
37979 1 sleep 100
您使用multiprocessing
而不是subprocess
是否有特殊原因?前者不打算用于创建旨在比父进程寿命更长的子进程;它用于创建子进程来执行可以有效地跨 CPU 并行化的工作,作为规避Global Interpreter Lock 的一种方式。 (出于讨论的目的,我忽略了multiprocessing
的分布式功能。)因此,multiprocessing
通常用于那些如果没有 GIL,您将使用线程的情况。 (注意,在这方面,multiprocessing
模块的 API 与 threading
模块的 API 非常相似。)
对于您帖子末尾的具体问题:(1)当父母终止时,python 没有任何责任杀死孩子。只有当父进程在退出之前将其杀死(或者整个进程组都被杀死)时,Web 服务器的子进程才会被杀死。 (2) 您链接到的方法看起来像是在尝试复制守护进程而不知道这样做的标准习语。有许多用于创建守护进程的包;您应该改用其中之一。
【讨论】:
subprocess 是我调度系统调用的首选模块,但使用 subprocess 启动后台 python 任务似乎不合适。你用过好的python-deamon库(比如python-deamon)吗? 背景/前景的区别是特定于 shell 中的作业控制;一般来说,在应用程序中使用这些术语来进行流程管理是没有意义的。在更一般的上下文中,守护进程是进程为自己执行的操作,使用subprocess.Popen
启动这样的进程是完全标准的。 python-daemon
很好;它有一个繁琐的 API,但经过实战考验,后者的质量很重要,因为很容易出错。以上是关于Python多处理和子进程的独立性的主要内容,如果未能解决你的问题,请参考以下文章