Python使用subprocess时如何在任意子进程结束时杀死所有子进程
任意子进程退出时自动终止其余子进程的实现方案
原代码的核心问题是使用串行proc.wait()逻辑,会阻塞在第一个子进程的等待上,无法实时感知其他子进程的退出状态,因此没法触发全局终止逻辑。
实现逻辑
- 保留原有
set_pdeathsig兜底逻辑,避免父进程意外退出时残留孤儿进程 - 放弃串行阻塞等待,改用低频率轮询非阻塞检查所有子进程的运行状态
- 一旦检测到任意子进程退出(无论正常结束还是异常被杀死),立刻遍历终止所有剩余存活子进程,先发送
SIGTERM给进程留优雅退出时间,超时未退出再发送SIGKILL强杀,最后回收所有进程资源避免僵尸进程 - 不依赖子进程侧添加任何代码,即使子进程被
SIGKILL强杀无法执行自定义逻辑,父进程也能正常检测到退出事件,可靠性远高于子进程主动杀父进程的方案
可直接运行的修正代码
import ctypes import os import signal import subprocess import time libc = ctypes.CDLL("libc.so.6") def set_pdeathsig(sig=signal.SIGTERM): def callable(): return libc.prctl(1, sig) return callable def cleanup_all_procs(proc_list): # 先发送SIGTERM,给进程留优雅退出的时间 for proc in proc_list: if proc.poll() is None: try: proc.terminate() except Exception: pass # 等待3秒,仍未退出的进程强制SIGKILL time.sleep(3) for proc in proc_list: if proc.poll() is None: try: proc.kill() except Exception: pass # 回收所有进程资源,避免僵尸进程 for proc in proc_list: try: proc.wait(timeout=1) except Exception: pass if __name__ == "__main__": procs = [] for i in range((os.cpu_count() * 2) - 1): proc = subprocess.Popen( ['python', "pythonscript_i_need_to_run/"], preexec_fn=set_pdeathsig(signal.SIGTERM) ) procs.append(proc) procs.append(subprocess.Popen( ["python", "other_pythonscript_i_need_to_run"], preexec_fn=set_pdeathsig(signal.SIGTERM) )) try: while True: # 非阻塞检查所有子进程状态 for proc in procs: if proc.poll() is not None: # 检测到任意进程退出,触发全局清理 cleanup_all_procs(procs) exit(0) # 100ms检查一次,CPU占用可忽略,可根据实时性要求调整间隔 time.sleep(0.1) except KeyboardInterrupt: # 捕获Ctrl+C手动中断场景,同样清理所有子进程 cleanup_all_procs(procs)
之前方案失效的原因说明
- 子进程内调用
os.kill(os.getppid(), signal.SIGTERM)不生效:一是子进程如果被SIGKILL强杀,根本没有机会执行这行代码;二是如果父进程提前退出,子进程会被init进程接管,getppid()拿到的不是原始父进程PID;三是父进程可能存在信号捕获/忽略逻辑,导致SIGTERM没有触发退出。 - 进程组方案不生效:大概率是启动子进程时没有正确创建/加入独立进程组,子进程默认继承父进程的进程组,直接杀进程组会把父进程本身也纳入杀死范围,逻辑容易出现冲突。
内容的提问来源于stack exchange,提问作者foxel
相关产品推荐
相关产品推荐

