确保子流程是死在退出Python程序
-
11-07-2019 - |
题
有没有一种方法,以确保所有创造的子流程是死在退出时间的蟒蛇的程序?通过子流程我的意思是那些有子流程.Popen().
如果没有,我应该迭代的所有发出的杀死,然后杀死-9?任何东西吸尘器?
解决方案
可以使用的 atexit对强> 对于这一点,和寄存器任何清理任务,你的程序退出时运行。
<强> atexit.register(FUNC [,* ARGS [,** kargs]])强>
在您的清理过程中,你也可以实现自己的等待,而当您需要的超时杀死它。
>>> import atexit
>>> import sys
>>> import time
>>>
>>>
>>>
>>> def cleanup():
... timeout_sec = 5
... for p in all_processes: # list of your processes
... p_sec = 0
... for second in range(timeout_sec):
... if p.poll() == None:
... time.sleep(1)
... p_sec += 1
... if p_sec >= timeout_sec:
... p.kill() # supported from python 2.6
... print 'cleaned up!'
...
>>>
>>> atexit.register(cleanup)
>>>
>>> sys.exit()
cleaned up!
注意强> - 注册功能将不被如果这个过程(父进程)被杀死运行
<强>下面的窗口的方法不再需要为Python> = 2.6 强>
下面是一种方法来杀死在窗口的处理。您POPEN对象有一个pid的属性,所以你可以通过调用它的成功= win_kill(p.pid)(需要的 pywin32 安装):
def win_kill(pid):
'''kill a process by specified PID in windows'''
import win32api
import win32con
hProc = None
try:
hProc = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, pid)
win32api.TerminateProcess(hProc, 0)
except Exception:
return False
finally:
if hProc != None:
hProc.Close()
return True
其他提示
在* nix的,也许使用进程组可以帮你 - 你能赶上你的子进程催生和子流程
if __name__ == "__main__":
os.setpgrp() # create new process group, become its leader
try:
# some code
finally:
os.killpg(0, signal.SIGKILL) # kill all processes in my group
的另一个考虑是将信号升级:从SIGTERM(对于kill
缺省信号)SIGKILL(a.k.a kill -9
)。等待的信号之间的短而得到的处理的机会,你kill -9
之前完全退出。
在subprocess.Popen.wait()
是确保他们死的唯一途径。事实上,POSIX操作系统的要求,你就等着你的儿女。许多* nix中的将创建一个“僵尸”的过程:一个死孩子的母没有等到
如果孩子是相当好写入时,它终止。通常情况下,儿童从管道的读取。关闭输入是一个很大的提示,它应该关店退出的孩子。
如果孩子有错误,并不会终止,则可能必须杀死它。您应该修复这个bug。
如果孩子是“服务 - 永远”的循环,而不是旨在终止,您应该杀了它,或者提供一些输入或消息,这将迫使它终止。
编辑。
在标准的操作系统的,你有os.kill( PID, 9 )
。杀-9恶劣,BTW。如果你可以用SIGABRT(6?)或SIGTERM(15)杀死他们,是比较客气的。
在Windows操作系统,你没有那个工作的os.kill
。看这个 ActiveState的配方在Windows终止进程。
我们有一个是WSGI服务器的子进程。要终止他们,我们做一个特殊的URL一个GET;这导致子清理并退出。
警告:Linux only!你可以让你的孩子接收信号的时其父母死亡。
首先安装python prctl==升级到1.5.0然后改变你的父母代码发动你的孩子流程如下
subprocess.Popen(["sleep", "100"], preexec_fn=lambda: prctl.set_pdeathsig(signal.SIGKILL))
什么这个说的是:
- 发射子流程:睡眠100
- 后forking和前exec的子流程,儿童的登记册"送我一个SIGKILL 当我父终止".
轮询()
检查子进程终止。 返回RETURNCODE属性。
我需要这个问题的一个小的变化(清理子流程,但不退出Python程序本身),并且由于它不是这里提到的其它的答案中:
p=subprocess.Popen(your_command, preexec_fn=os.setsid)
os.killpg(os.getpgid(p.pid), 15)
setsid
将在一个新的会话中运行该程序,从而分配新进程组它和它的孩子。呼吁它os.killpg
因而不会打倒自己的Python进程也。
OriP位的回答是有益的,但有它杀死你的进程,并返回一个错误代码父下行。我避免了这样的:
class CleanChildProcesses:
def __enter__(self):
os.setpgrp() # create new process group, become its leader
def __exit__(self, type, value, traceback):
try:
os.killpg(0, signal.SIGINT) # kill all processes in my group
except KeyboardInterrupt:
# SIGINT is delievered to this process as well as the child processes.
# Ignore it so that the existing exception, if any, is returned. This
# leaves us with a clean exit code if there was no exception.
pass
然后:
with CleanChildProcesses():
# Do your work here
当然,你可以使用try /做到这一点,除了/最后,但你必须单独处理的特殊和非特殊情况下。
有没有一种方法,以确保所有已创建子进程正处在一个Python程序的退出时间死了吗?由子我的意思是那些具有subprocess.Popen()创建。
您可能违反封装的测试的所有POPEN进程已经做终止
subprocess._cleanup()
print subprocess._active == []
如果不是,我应该遍历所有发行杀死,然后杀死-9?任何清洁器?
您不能确保所有的子进程都没有走出去,杀死每一位幸存者,死了。但是,如果你有这样的问题,很可能是因为你有一个更深层次的设计问题。
一个用于窗口解决方案可以是使用Win32 API作业例如如何自动销毁子进程在Windows?
下面是一个现有Python实现
我确实需要做到这一点,但它涉及到运行远程命令。我们希望能够通过关闭与服务器的连接,以停止进程。另外,如果,例如,你在Python REPL运行,你可以选择为前台运行,如果你希望能够使用Ctrl-C退出。
import os, signal, time
class CleanChildProcesses:
"""
with CleanChildProcesses():
Do work here
"""
def __init__(self, time_to_die=5, foreground=False):
self.time_to_die = time_to_die # how long to give children to die before SIGKILL
self.foreground = foreground # If user wants to receive Ctrl-C
self.is_foreground = False
self.SIGNALS = (signal.SIGHUP, signal.SIGTERM, signal.SIGABRT, signal.SIGALRM, signal.SIGPIPE)
self.is_stopped = True # only call stop once (catch signal xor exiting 'with')
def _run_as_foreground(self):
if not self.foreground:
return False
try:
fd = os.open(os.ctermid(), os.O_RDWR)
except OSError:
# Happens if process not run from terminal (tty, pty)
return False
os.close(fd)
return True
def _signal_hdlr(self, sig, framte):
self.__exit__(None, None, None)
def start(self):
self.is_stopped = False
"""
When running out of remote shell, SIGHUP is only sent to the session
leader normally, the remote shell, so we need to make sure we are sent
SIGHUP. This also allows us not to kill ourselves with SIGKILL.
- A process group is called orphaned when the parent of every member is
either in the process group or outside the session. In particular,
the process group of the session leader is always orphaned.
- If termination of a process causes a process group to become orphaned,
and some member is stopped, then all are sent first SIGHUP and then
SIGCONT.
consider: prctl.set_pdeathsig(signal.SIGTERM)
"""
self.childpid = os.fork() # return 0 in the child branch, and the childpid in the parent branch
if self.childpid == 0:
try:
os.setpgrp() # create new process group, become its leader
os.kill(os.getpid(), signal.SIGSTOP) # child fork stops itself
finally:
os._exit(0) # shut down without going to __exit__
os.waitpid(self.childpid, os.WUNTRACED) # wait until child stopped after it created the process group
os.setpgid(0, self.childpid) # join child's group
if self._run_as_foreground():
hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN) # ignore since would cause this process to stop
self.controlling_terminal = os.open(os.ctermid(), os.O_RDWR)
self.orig_fore_pg = os.tcgetpgrp(self.controlling_terminal) # sends SIGTTOU to this process
os.tcsetpgrp(self.controlling_terminal, self.childpid)
signal.signal(signal.SIGTTOU, hdlr)
self.is_foreground = True
self.exit_signals = dict((s, signal.signal(s, self._signal_hdlr))
for s in self.SIGNALS)
def stop(self):
try:
for s in self.SIGNALS:
#don't get interrupted while cleaning everything up
signal.signal(s, signal.SIG_IGN)
self.is_stopped = True
if self.is_foreground:
os.tcsetpgrp(self.controlling_terminal, self.orig_fore_pg)
os.close(self.controlling_terminal)
self.is_foreground = False
try:
os.kill(self.childpid, signal.SIGCONT)
except OSError:
"""
can occur if process finished and one of:
- was reaped by another process
- if parent explicitly ignored SIGCHLD
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
- parent has the SA_NOCLDWAIT flag set
"""
pass
os.setpgrp() # leave the child's process group so I won't get signals
try:
os.killpg(self.childpid, signal.SIGINT)
time.sleep(self.time_to_die) # let processes end gracefully
os.killpg(self.childpid, signal.SIGKILL) # In case process gets stuck while dying
os.waitpid(self.childpid, 0) # reap Zombie child process
except OSError as e:
pass
finally:
for s, hdlr in self.exit_signals.iteritems():
signal.signal(s, hdlr) # reset default handlers
def __enter__(self):
if self.is_stopped:
self.start()
def __exit__(self, exit_type, value, traceback):
if not self.is_stopped:
self.stop()
由于马尔科姆汉德利用于初始设计。完成在Linux python2.7。
找出用于Linux的溶液(不安装使用prctl):
def _set_pdeathsig(sig=signal.SIGTERM):
"""help function to ensure once parent process exits, its childrent processes will automatically die
"""
def callable():
libc = ctypes.CDLL("libc.so.6")
return libc.prctl(1, sig)
return callable
subprocess.Popen(your_command, preexec_fn=_set_pdeathsig(signal.SIGTERM))
这是我做我的POSIX的应用程序:
当你的应用存在调用这个类的杀()方法: http://www.pixelbeat.org/libs/subProcess.py
实施例使用这里: http://code.google.com/p/ fslint /源/浏览/中继/ fslint桂#608
您可以尝试subalive
,包我写了类似的问题。它通过RPC使用周期性活着平,并且当所述主停止活着坪由于某种原因,从属进程自动终止。
https://github.com/waszil/subalive
示例主:
from subalive import SubAliveMaster
# start subprocess with alive keeping
SubAliveMaster(<path to your slave script>)
# do your stuff
# ...
示例从属子:
from subalive import SubAliveSlave
# start alive checking
SubAliveSlave()
# do your stuff
# ...