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

关闭Python进程后保持子进程持续运行的实现问题

解决主进程终止后子进程继续运行的问题

这个问题本质是进程组与信号传递导致的:当你用shell=True时,实际启动的是一个shell进程,它才是yes命令的父进程;而主进程终止时,shell进程会收到SIGHUP信号(终端挂起信号),进而把这个信号转发给它的子进程yes,导致yes跟着退出。哪怕不用shell=True,子进程和主进程默认在同一个进程组,主进程终止(比如关闭终端)时,整个进程组都会收到SIGHUP,同样会终止子进程。

下面给你几个可靠的解决办法:

方法1:脱离进程组(推荐,无需shell)

直接给Popen加上start_new_session=True参数,让子进程成为新会话的领头进程,脱离主进程的进程组,这样主进程终止时,子进程不会收到SIGHUP信号。同时尽量避免用shell=True,减少不必要的中间进程:

from subprocess import Popen

args = ['yes']
# 启动子进程并创建新会话
Popen(args, stdout=None, stdin=None, stderr=None, start_new_session=True)

方法2:结合nohup使用(适合必须用shell的场景)

如果因为某些原因必须用shell=True,可以用nohup命令让yes忽略SIGHUP信号,同时重定向输出避免生成nohup.out文件:

from subprocess import Popen

# nohup让进程忽略SIGHUP,&让shell在后台启动进程,重定向输出到/dev/null
Popen('nohup yes > /dev/null 2>&1 &', shell=True)

方法3:创建孤儿进程(底层实现方式)

通过两次fork创建孤儿进程,让最终的子进程被init或systemd接管,彻底脱离主进程的控制:

import os
import subprocess

if os.fork() == 0:
    # 第一次fork的子进程,创建新会话
    os.setsid()
    if os.fork() == 0:
        # 第二次fork的孙子进程,此时父进程会变成init/systemd,成为孤儿进程
        subprocess.run(['yes'], stdout=None, stdin=None, stderr=None)
    # 第一个子进程退出,避免成为僵尸进程
    os._exit(0)
# 主进程等待第一个子进程退出
os.wait()

简单总结:优先用方法1,简洁且避免shell带来的额外问题;如果必须用shell,选方法2;方法3适合需要更底层控制的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:41:25