Ubuntu下Python通过subprocess启动Jar后脚本卡顿、进程无法杀死
问题原因
- 错误使用shell后台符&:subprocess模块默认
shell=False,参数列表里的&会被当作java命令的普通参数传递,不会被解析为后台运行指令。java命令收到无效参数后要么抛出异常卡住,要么进入等待状态,导致Popen调用直接挂住,后续代码无法执行。 - IO重定向不完整:你仅重定向了stdout到空设备,没有处理stdin和stderr。如果jar进程需要读取标准输入(比如确认用户许可)、或者向stderr输出错误日志写满缓冲区,都会导致进程阻塞,连带父脚本卡住。
- 上层调用逻辑错误:上层脚本使用
subprocess.run调用当前脚本时也添加了&,同样存在参数解析错误的问题,且subprocess.run本身是同步等待子进程执行完成才返回的,根本无法达到后台运行的效果。
修复方案
1. 修改当前脚本的java进程启动代码
将原Popen调用
p2 = subprocess.Popen(["java", "-jar", "serverstarter-2.0.1.jar", "&"], stdout=subprocess.DEVNULL)
替换为:
p2 = subprocess.Popen( ["java", "-jar", "serverstarter-2.0.1.jar"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL )
说明:去掉无效的&参数,全量重定向三个标准IO流,避免IO阻塞导致的卡顿。如果需要排查jar本身的运行问题,可以临时将stderr改为输出到本地日志文件。
2. 修改上层调用脚本的逻辑
将原调用代码
subprocess.run(["python3", p, "&"], stdout=subprocess.DEVNULL)
替换为:
subprocess.Popen( ["python3", p], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL )
说明:subprocess.Popen会直接返回,让子脚本后台运行,符合你的预期需求,不需要额外加&。
可选优化(杀进程更彻底)
如果出现p2.kill()无法完全杀死java衍生的子进程的情况,可以在创建Popen时添加start_new_session=True参数,后续杀进程时调用os.killpg(os.getpgid(p2.pid), signal.SIGTERM)杀死整个进程组即可。
内容的提问来源于stack exchange,提问作者zeroerrors0945
相关产品推荐
相关产品推荐

