在Python中,如果父进程被杀,如何杀死子进程

34 投票
4 回答
30702 浏览
提问于 2025-04-18 18:48

我正在从一个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

当一个进程结束时,它会尝试终止所有它的守护子进程。

撰写回答