Python subprocess.run超时未终止子进程问题求助
问题原因及解决方案
核心问题1:shell=True导致超时无法终止实际转换进程
当使用shell=True时,subprocess.run启动的是系统shell进程(如bash),再由shell去启动ebook-convert。此时timeout参数只会终止shell进程,而ebook-convert会成为孤儿进程被系统接管,继续在后台运行,导致你的主程序要么卡在等待状态,要么看似正常执行但实际转换任务并未停止。
核心问题2:代码结构错误,超时异常未被捕获
你的subprocess.run调用在try块之外,一旦触发TimeoutExpired异常,会直接终止程序,无法进入后续的异常处理逻辑。
解决方案1:移除shell=True(推荐)
直接传递命令参数列表给subprocess.run,这样timeout会直接终止ebook-convert进程,同时避免shell注入风险,代码更安全:
try: cmd = ['ebook-convert', filename, outfile] process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=77400) ConversionFile.set_to_finished(options.get('uuid')) if process.stderr and "error" in process.stderr.decode("utf-8"): return {'error': process.stderr.decode("utf-8")} return [outfile] except subprocess.TimeoutExpired: print("转换超时,已终止进程") return {'error': '转换超时'} except Exception as e: print(str(e)) return {'error': str(e)}
解决方案2:保留shell=True但终止整个进程组
如果因特殊需求必须使用shell=True,可以通过start_new_session=True创建新的进程组,超时后终止整个进程组,确保ebook-convert也被杀死:
import os import signal try: cmd = 'ebook-convert "%s" "%s"' % (filename, outfile) # 创建新进程组,关联shell和子进程 process = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=77400, start_new_session=True) ConversionFile.set_to_finished(options.get('uuid')) if process.stderr and "error" in process.stderr.decode("utf-8"): return {'error': process.stderr.decode("utf-8")} return [outfile] except subprocess.TimeoutExpired: # 终止整个进程组,包含shell和ebook-convert os.killpg(os.getpgid(process.pid), signal.SIGTERM) # 强制终止(可选,确保进程彻底退出) os.killpg(os.getpgid(process.pid), signal.SIGKILL) print("转换超时,已终止所有相关进程") return {'error': '转换超时'} except Exception as e: print(str(e)) return {'error': str(e)}
内容的提问来源于stack exchange,提问作者nadermx
相关产品推荐
相关产品推荐

