Flask启动的Linux进程执行后变为defunct的解决方法求助
Flask子进程变为僵尸进程的解决方法
问题描述
我需要用Flask应用通过特定端点管理命令执行,同时设置第二个端点监控Flask触发的进程。目前整体思路已经明确,但遇到一个问题:进程执行完毕后,启动的进程会变成defunct(僵尸进程)。我知道这是因为创建进程的父进程(我的Flask应用)仍在运行。我尝试过不同方式启动进程,也试过强制终止,但都没用。相关代码如下:
try: res = Popen("my_script.sh", universal_newlines=True, start_new_session=True, stdout=PIPE, stderr=STDOUT, cwd="/", shell=True, env=environ.copy(), close_fds=True ) # 该函数尝试处理进程终止逻辑 # 必须用独立进程,这样应用才能在后台进程运行时返回响应 multiprocessing.Process(target=_ManagerExecutor.__handle_process, args=(res,)).start() return result except Exception as e: ...
@classmethod def __handle_process(cls, process: Popen): while True: output = process.stdout.readline() if not output: break #... 其他业务逻辑 process.poll() result: bool = process.returncode != 0 try: # 尝试强制杀死进程组,但无效 killpg(getpgid(process.pid), SIGTERM) except Exception: pass
核心原因
僵尸进程产生的本质是子进程结束后,父进程未调用wait()/waitpid()回收其退出状态。当前代码中,process.poll()仅用于查询进程状态,不会释放僵尸进程的资源;而进程结束后调用killpg属于无效操作,完全无法解决问题。另外,负责处理Popen进程的multiprocessing.Process作为父进程,必须承担回收子进程资源的责任。
修复方案
方案1:使用communicate()自动回收资源
communicate()会自动读取子进程的所有输出,阻塞到进程结束后调用wait()回收资源,彻底避免僵尸进程:
修改后的__handle_process方法:
@classmethod def __handle_process(cls, process: Popen): try: # 读取所有输出并等待进程结束,自动回收资源 output, _ = process.communicate() # 逐行处理输出(按需调整) for line in output.splitlines(): # ... 你的业务逻辑代码 pass # 获取进程退出状态 result: bool = process.returncode != 0 except Exception as e: # 异常处理逻辑 pass
方案2:保留逐行读取,显式调用wait()
如果需要实时处理进程输出,不能用communicate(),则在循环结束后必须显式调用process.wait()回收资源:
@classmethod def __handle_process(cls, process: Popen): try: while True: output = process.stdout.readline() if not output: # 确认进程已结束 if process.poll() is not None: break continue # ... 你的业务逻辑代码 # 显式回收子进程,消除僵尸 process.wait() result: bool = process.returncode != 0 except Exception as e: pass
额外优化建议
- 移除
shell=True:如果脚本路径固定,改用列表形式传参(如["/full/path/to/my_script.sh"]),减少安全风险,同时避免额外的shell子进程产生僵尸。 - 按需使用
start_new_session:如果不需要独立会话组,可去掉该参数,简化进程管理。
内容的提问来源于stack exchange,提问作者Matteo Pasini
相关产品推荐
相关产品推荐

