You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 00:55:25