pup*_*eno 59 python subprocess kill zombie-process
有没有办法确保所有创建的子进程在Python程序的退出时间都死了?通过子进程,我指的是使用subprocess.Popen()创建的.
如果没有,我应该迭代所有发出的杀戮然后杀死-9?什么更干净?
mon*_*kut 45
您可以使用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!
Run Code Online (Sandbox Code Playgroud)
注 - 如果此进程(父进程)被终止,则不会运行已注册的函数.
python> = 2.6不再需要以下windows方法
这是一种在Windows中杀死进程的方法.你的Popen对象有一个pid属性,所以你可以通过success = 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
Run Code Online (Sandbox Code Playgroud)
ori*_*rip 33
在*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
Run Code Online (Sandbox Code Playgroud)
另一个考虑因素是升级信号:从SIGTERM(默认信号kill)到SIGKILL(aka kill -9).在信号之间等待一会儿,让过程有机会在你之前干净地退出kill -9.
S.L*_*ott 14
这subprocess.Popen.wait()是确保他们死亡的唯一方法.实际上,POSIX OS要求您等待您的孩子.许多*nix将创建一个"僵尸"过程:一个死孩子,父母没有等待.
如果孩子写得合理,它就会终止.孩子们常常从PIPE上读到.关闭输入是一个很大的暗示,孩子应该关闭购物和退出.
如果孩子有虫子并且没有终止,你可能不得不杀死它.你应该修复这个bug.
如果孩子是"永远服务"循环,并且不是为了终止,你应该杀死它或者提供一些输入或消息来强制它终止.
编辑.
在标准操作系统中,你有os.kill( PID, 9 ).Kill -9很苛刻,BTW.如果你能用SIGABRT(6?)或SIGTERM(15)杀死它们,那就更有礼貌了.
在Windows操作系统中,您没有os.kill可行的功能.查看此ActiveState配方以终止Windows中的进程.
我们有子进程是WSGI服务器.要终止它们,我们在特殊URL上进行GET; 这导致孩子清理并退出.
小智 6
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
Run Code Online (Sandbox Code Playgroud)
进而:
with CleanChildProcesses():
# Do your work here
Run Code Online (Sandbox Code Playgroud)
当然你可以使用 try/ except/finally 来做到这一点,但是你必须分别处理异常和非异常情况。
找出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))
Run Code Online (Sandbox Code Playgroud)
我需要这个问题的一个小变化(清理子进程,但不退出Python程序本身),因为这里在其他答案中没有提到它:
p=subprocess.Popen(your_command, preexec_fn=os.setsid)
os.killpg(os.getpgid(p.pid), 15)
Run Code Online (Sandbox Code Playgroud)
setsid将在新会话中运行该程序,从而为其及其子进程分配一个新的进程组。因此调用os.killpg它也不会关闭你自己的 python 进程。
警告:仅限 Linux!您可以让您的孩子在其父母去世时收到信号。
首先安装 python-prctl==1.5.0 然后更改您的父代码以启动您的子进程,如下所示
subprocess.Popen(["sleep", "100"], preexec_fn=lambda: prctl.set_pdeathsig(signal.SIGKILL))
Run Code Online (Sandbox Code Playgroud)
这说的是:
| 归档时间: |
|
| 查看次数: |
53771 次 |
| 最近记录: |