确保子进程在退出 Python 程序时死亡
有没有办法确保所有创建的子进程在Python程序退出时都死掉? 我所说的子进程是指那些使用 subprocess.Popen() 创建的进程。
如果不是,我是否应该迭代所有发出的kills,然后kills -9? 有什么更干净的吗?
Is there a way to ensure all created subprocess are dead at exit time of a Python program? By subprocess I mean those created with subprocess.Popen().
If not, should I iterate over all of the issuing kills and then kills -9? anything cleaner?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
您可以使用 atexit 来执行此操作,并注册任何清理操作程序退出时要运行的任务。
atexit.register(func[, *args[, **kargs]])
在清理过程中,您还可以实现自己的等待,并在发生所需超时时终止它。
注意 -- 如果该进程(父进程)被终止,注册的函数将不会运行。
对于 python >= 2.6 不再需要下面的 windows 方法
下面是在 windows 中杀死进程的方法。 您的 Popen 对象具有 pid 属性,因此您可以通过 success = win_kill(p.pid) 调用它(需要 pywin32 安装):
You can use atexit for this, and register any clean up tasks to be run when your program exits.
atexit.register(func[, *args[, **kargs]])
In your cleanup process, you can also implement your own wait, and kill it when a your desired timeout occurs.
Note -- Registered functions won't be run if this process (parent process) is killed.
The following windows method is no longer needed for python >= 2.6
Here's a way to kill a process in windows. Your Popen object has a pid attribute, so you can just call it by success = win_kill(p.pid) (Needs pywin32 installed):
在 *nix 上,也许使用进程组可以帮助您 - 您也可以捕获子进程生成的子进程。
另一个考虑因素是升级信号:从 SIGTERM(
kill
的默认信号)到 SIGKILL(又名kill -9
)。 在信号之间等待一小会儿,让进程有机会彻底退出,然后再kill -9
。On *nix's, maybe using process groups can help you out - you can catch subprocesses spawned by your subprocesses as well.
Another consideration is to escalate the signals: from SIGTERM (default signal for
kill
) to SIGKILL (a.k.akill -9
). Wait a short while between the signals to give the process a chance to exit cleanly before youkill -9
it.subprocess.Popen.wait() 是确保它们已死亡的唯一方法。 事实上,POSIX 操作系统要求您等待您的孩子。 许多 *nix 会创建一个“僵尸”进程:一个父进程没有等待的死亡子进程。
如果子进程写得相当好,它就会终止。 通常,孩子们会从 PIPE 中阅读。 关闭输入是对孩子的一个重要暗示,它应该关闭商店并退出。
如果子进程有 bug 并且没有终止,您可能必须杀死它。 你应该修复这个错误。
如果子循环是“永远服务”循环,并且未设计为终止,则您应该终止它或提供一些输入或消息来强制其终止。
编辑。
在标准操作系统中,您有 os.kill( PID, 9 ) 。 顺便说一句,Kill -9 很严酷。 如果你可以用 SIGABRT (6?) 或 SIGTERM (15) 杀死它们,那就更有礼貌了。
在 Windows 操作系统中,您没有可用的
os.kill
。 查看此ActiveState Recipe,用于终止 Windows 中的进程。我们有作为 WSGI 服务器的子进程。 为了终止它们,我们对一个特殊的 URL 执行 GET; 这会导致孩子清理并退出。
The
subprocess.Popen.wait()
is the only way to assure that they're dead. Indeed, POSIX OS's require that you wait on your children. Many *nix's will create a "zombie" process: a dead child for which the parent didn't wait.If the child is reasonably well-written, it terminates. Often, children read from PIPE's. Closing the input is a big hint to the child that it should close up shop and exit.
If the child has bugs and doesn't terminate, you may have to kill it. You should fix this bug.
If the child is a "serve-forever" loop, and is not designed to terminate, you should either kill it or provide some input or message which will force it to terminate.
Edit.
In standard OS's, you have
os.kill( PID, 9 )
. Kill -9 is harsh, BTW. If you can kill them with SIGABRT (6?) or SIGTERM (15) that's more polite.In Windows OS, you don't have an
os.kill
that works. Look at this ActiveState Recipe for terminating a process in Windows.We have child processes that are WSGI servers. To terminate them we do a GET on a special URL; this causes the child to clean up and exit.
找出Linux下的解决方案(不安装prctl):
Find out a solution for linux (without installing prctl):
警告:仅限 Linux! 您可以让您的孩子在父母去世时收到信号。
首先安装 python-prctl==1.5.0 然后更改父代码以启动子进程,如下所示
这意味着:
当我的父母终止时”。
Warning: Linux-only! You can make your child receive a signal when its parent dies.
First install python-prctl==1.5.0 then change your parent code to launch your child processes as follows
What this says is:
when my parent terminates".
orip 的答案很有帮助,但有一个缺点,它会终止您的进程并向您的父进程返回错误代码。 我这样避免了:
然后:
当然你可以用 try/ except/finally 来做到这一点,但你必须分别处理异常和非异常情况。
orip's answer is helpful but has the downside that it kills your process and returns an error code your parent. I avoided that like this:
And then:
Of course you can do this with try/except/finally but you have to handle the exceptional and non-exceptional cases separately.
我需要这个问题的一个小变体(清理子进程,但不退出Python程序本身),并且因为这里没有在其他答案中提到它:
setsid
将在新会话中运行该程序,从而为其及其子进程分配一个新的进程组。 因此,在其上调用 os.killpg 也不会关闭您自己的 python 进程。I needed a small variation of this problem (cleaning up subprocesses, but without exiting the Python program itself), and since it's not mentioned here among the other answers:
setsid
will run the program in a new session, thus assigning a new process group to it and its children. callingos.killpg
on it thus won't bring down your own python process also.Windows 的解决方案可能是使用 win32 job api,例如 如何我是否会自动销毁 Windows 中的子进程?
这是现有的 python 实现
https://gist。 github.com/ubershmekel/119697afba2eaecc6330
A solution for windows may be to use the win32 job api e.g. How do I automatically destroy child processes in Windows?
Here's an existing python implementation
https://gist.github.com/ubershmekel/119697afba2eaecc6330
您可能会违反封装并测试所有 Popen 进程是否已终止
如果不出去杀死每个幸存者,就无法确保所有子进程都已死亡。 但如果你遇到这个问题,很可能是因为你有更深层次的设计问题。
You could violate encapsulation and test that all Popen processes have terminated by doing
You cannot ensure that all subprocesses are dead without going out and killing every survivor. But if you have this problem, it is probably because you have a deeper design problem.
我实际上需要这样做,但它涉及运行远程命令。 我们希望能够通过关闭与服务器的连接来停止进程。 此外,例如,如果您正在 python repl 中运行,并且希望能够使用 Ctrl-C 退出,则可以选择作为前台运行。
感谢马尔科姆·汉德利 (Malcolm Handley) 的初步设计。 在linux上使用python2.7完成。
I actually needed to do this, but it involved running remote commands. We wanted to be able to stop the processes by closing the connection to the server. Also, if, for example, you are running in the python repl, you can select to run as foreground if you want to be able to use Ctrl-C to exit.
Thanks to Malcolm Handley for the initial design. Done with python2.7 on linux.
你可以尝试
subalive
,这是我为类似问题编写的一个包。 它通过 RPC 使用定期的活动 ping,当主站由于某种原因停止活动 ping 时,从属进程会自动终止。https://github.com/waszil/subalive
主进程示例:
从属子进程示例:
You can try
subalive
, a package I wrote for similar problem. It uses periodic alive ping via RPC, and the slave process automatically terminates when the master stops alive pings for some reason.https://github.com/waszil/subalive
Example for master:
Example for slave subprocess:
通过生成一个单独的进程来监督销毁,可以在 Windows 上获得更多保证。
It's possible to get some more guarantees on windows by spawning a separate process to oversee the destruction.
这就是我为我的 posix 应用程序所做的:
当您的应用程序存在时,调用此类的 Kill() 方法:
http://www.pixelbeat.org/libs/subProcess.py
此处使用示例:
http://code.google.com/p/ fslint/源/浏览/主干/fslint-gui#608
This is what I did for my posix app:
When your app exists call the kill() method of this class:
http://www.pixelbeat.org/libs/subProcess.py
Example use here:
http://code.google.com/p/fslint/source/browse/trunk/fslint-gui#608
python 代码帮助:
http://docs.python.org/dev/library/subprocess .html#subprocess.Popen.wait
help for python code:
http://docs.python.org/dev/library/subprocess.html#subprocess.Popen.wait