Python多进程:捕获SIGINT/SIGTERM实现优雅退出问题排查
问题分析与解决
你的代码主要存在以下几个导致优雅退出失败的问题:
1. 主进程循环无延迟,且每次循环创建新进程/Pipe
主进程的while not killer.kill_now循环会疯狂调用main(),瞬间创建大量子进程和Pipe资源,不仅浪费系统资源,还会导致收到SIGINT信号时,当前main()可能卡在parent_conn.recv()阻塞状态,无法及时响应退出标记。
2. 未正确关闭Pipe的父端
每次parent_conn.recv()后没有关闭父端连接,会造成资源泄漏,也会影响进程的正常退出。
3. 子进程未处理信号(当前场景不明显,但长期运行场景会出问题)
如果后续arraySender改成耗时任务,子进程不会响应SIGINT信号,主进程退出时无法优雅终止子进程。
修改后的代码
Process.py
from multiprocessing import Process, Pipe from Communication import arraySender import time import signal class GracefulKiller: kill_now = False def __init__(self): signal.signal(signal.SIGINT, self.exit_gracefully) signal.signal(signal.SIGTERM, self.exit_gracefully) def exit_gracefully(self, *args): self.kill_now = True def main(killer): parent_conn, child_conn = Pipe() p = Process(target=arraySender, args=(child_conn, True)) p.start() # 带超时的recv,避免一直阻塞无法响应退出信号 try: if parent_conn.poll(timeout=1): print(parent_conn.recv()) except Exception as e: print(f"接收数据出错: {e}") finally: parent_conn.close() p.join() # 等待子进程结束后再退出 if __name__ == '__main__': killer = GracefulKiller() while not killer.kill_now: main(killer) time.sleep(1) # 添加延迟,避免频繁创建进程
Communication.py
import numpy from multiprocessing import Pipe import signal def arraySender(child_conn, sendData): # 给子进程也添加信号处理,确保能优雅退出 def handle_signal(*args): child_conn.close() exit(0) signal.signal(signal.SIGINT, handle_signal) signal.signal(signal.SIGTERM, handle_signal) if sendData: try: child_conn.send(numpy.random.randint(0, high=10, size=15, dtype=int)) finally: child_conn.close()
关键修改说明
- 给主循环添加
time.sleep(1),避免无限制创建子进程,降低资源占用。 - 使用
parent_conn.poll(timeout=1)替代直接recv(),让主进程每隔1秒检查一次退出标记,不会一直阻塞。 - 所有Pipe连接都在
finally块中关闭,确保资源释放。 - 子进程添加信号处理逻辑,即使是耗时任务也能响应退出信号。
- 主进程中调用
p.join()等待子进程结束,避免子进程成为僵尸进程。
内容的提问来源于stack exchange,提问作者Samuele Mecenero
相关产品推荐
相关产品推荐

