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

Python应用中SIGINT后执行子进程的解决方案

解决SIGINT中断后子进程无法执行的问题

这个问题我之前也碰到过,核心原因是SIGINT信号会传递给整个进程组——当你按下Ctrl+C触发KeyboardInterrupt时,当前进程组里的所有进程(包括之后启动的子进程)都会收到这个中断信号,导致save_work()里的hadoop命令刚启动就被终止。下面给你几个实用的解决办法:

方法1:让子进程脱离当前进程组

通过修改subprocess.Popen的参数,让子进程在独立的进程组/会话中运行,这样就不会继承父进程的SIGINT信号:

跨平台方案(Unix/Linux优先,Windows需调整)

使用start_new_session=True参数,让子进程创建新的会话:

cmd = r"hadoop fs -put '{}' '{}'".format(src, dest)
process = subprocess.Popen(
    cmd, 
    shell=True, 
    stdout=subprocess.PIPE, 
    stderr=subprocess.STDOUT,
    start_new_session=True  # 关键:子进程将在新会话中运行,不受父进程组信号影响
)
# 等待子进程完成并获取输出
stdout, _ = process.communicate()

Unix/Linux专属方案

使用preexec_fn=os.setpgrp将子进程设为新进程组的组长:

import os

cmd = r"hadoop fs -put '{}' '{}'".format(src, dest)
process = subprocess.Popen(
    cmd, 
    shell=True, 
    stdout=subprocess.PIPE, 
    stderr=subprocess.STDOUT,
    preexec_fn=os.setpgrp  # Unix下生效:让子进程成为新进程组的组长,脱离原进程组
)
stdout, _ = process.communicate()

方法2:临时忽略SIGINT信号再恢复

在启动子进程前,先让父进程忽略SIGINT信号,子进程启动后再恢复原来的信号处理逻辑。这样子进程启动时不会继承被忽略的信号状态,就能正常执行:

import signal

class Main(object):
    def do_stuff(self):
        # 你的核心业务逻辑
        ...
    def save_work(self):
        # 先保存原本的SIGINT处理函数
        original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
        try:
            # 此时启动子进程,不会收到SIGINT信号
            cmd = r"hadoop fs -put '{}' '{}'".format(src, dest)
            process = subprocess.Popen(
                cmd, 
                shell=True, 
                stdout=subprocess.PIPE, 
                stderr=subprocess.STDOUT
            )
            stdout, _ = process.communicate()
            # 可以在这里处理子进程的输出
            print("保存完成,输出:", stdout.decode())
        finally:
            # 无论成功失败,都恢复原来的SIGINT处理
            signal.signal(signal.SIGINT, original_sigint_handler)
    def __init__(self):
        try:
            self.do_stuff()
        except KeyboardInterrupt:
            print("收到中断信号,正在保存工作...")
        self.save_work()

方法3:借助shell命令隔离信号

如果你的场景依赖shell=True,可以在hadoop命令前加上nohup或者setsid,让子进程脱离当前进程组:

# 使用nohup让命令忽略挂起信号,同时脱离进程组
cmd = r"nohup hadoop fs -put '{}' '{}' > /dev/null 2>&1".format(src, dest)
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
process.wait()

注意:> /dev/null 2>&1是把nohup的输出重定向到空设备,如果你需要保留输出,可以改成指定日志文件路径。

内容的提问来源于stack exchange,提问作者Stefan Papp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:51:14