在Python中,如果父进程被杀,如何杀死子进程
我正在从一个Python脚本中启动5个不同的进程,像这样:
p = multiprocessing.Process(target=some_method,args=(arg,))
p.start()
我的问题是,当父进程(主脚本)被杀掉时,子进程仍然在运行。
有没有办法在父进程被杀掉时,也把这些子进程一起杀掉呢?
编辑:
我正在尝试这个:
p = multiprocessing.Process(target=client.start,args=(self.query_interval,))
p.start()
atexit.register(p.terminate)
但是这似乎没有效果。
4 个回答
0
我的情况是使用一个 Queue
对象来和子进程进行通信。不知道为什么,接受的答案中提到的 daemon
标志并没有起作用。这里有一个简单的例子,说明如何让子进程优雅地结束。
主要的思路是每隔一秒暂停子进程的工作,检查一下父进程是否还活着。如果父进程不在了,我们就关闭队列并退出。
注意,如果主进程是通过 SIGKILL
被杀掉,这种方法也能有效。
import ctypes, sys
import multiprocessing as mp
worker_queue = mp.Queue(maxsize=10)
# flag to communicate the parent's death to all children
alive = mp.Value(ctypes.c_bool, lock=False)
alive.value = True
def worker():
while True:
# fake work
data = 99.99
# submit finished work to parent, while checking if parent has died
queued = False
while not queued:
# note here we do not block indefinitely, so we can check if parent died
try:
worker_queue.put(data, block=True, timeout=1.0)
queued = True
except: pass
# check if parent process is alive still
par_alive = mp.parent_process().is_alive()
if not (par_alive and alive.value):
# for some reason par_alive is only False for one of the children;
# notify the others that the parent has died
alive.value = False
# appears we need to close the queue before sys.exit will work
worker_queue.close()
# for more dramatic shutdown, could try killing child process;
# wp.current_process().kill() does not work, though you could try
# calling os.kill directly with the child PID
sys.exit(1)
# launch worker processes
for i in range(4):
child = mp.Process(target=worker)
child.start()
2
如果你能获取到父进程的ID,可以使用类似下面的代码:
import os
import sys
import psutil
def kill_child_proc(ppid):
for process in psutil.process_iter():
_ppid = process.ppid()
if _ppid == ppid:
_pid = process.pid
if sys.platform == 'win32':
process.terminate()
else:
os.system('kill -9 {0}'.format(_pid))
kill_child_proc(<parent_pid>)
7
子进程并不会知道父进程的死亡,只有父进程会知道子进程的情况。
不过,当一个进程结束时,它打开的所有文件描述符都会被关闭。如果另一个进程在读取这个文件描述符(比如管道)时,它会收到这个关闭的通知。
所以,父进程可以在创建子进程之前先建立一个管道(或者直接把标准输入设置为管道),然后子进程可以选择这个管道来读取。当父进程关闭管道的一端时,子进程会收到可以读取的通知。这需要子进程运行一个主循环,或者至少定期调用选择函数。如果你不想这样做,就需要一个管理进程来处理,但如果这个管理进程被杀掉,事情又会出问题。
31
我自己也遇到过同样的问题,这里有一个解决办法:
在调用 p.start()
之前,你可以设置 p.daemon=True
。然后就像这里提到的 python.org multiprocessing
当一个进程结束时,它会尝试终止所有它的守护子进程。