Python运行bat批处理文件如何不阻塞后续程序执行
问题根因
你遇到的阻塞问题来自subprocess.call()的默认行为:这个方法是阻塞式调用,启动子进程后会一直挂起等待,直到子进程完全退出才会执行下一行代码。你的bat脚本启动后持续常驻不退出,主程序自然会一直卡在启动bat的这一行,永远走不到后续逻辑。
另外你贴的代码里subprocess存在拼写错误(写为了subpprocess),运行时也会触发报错。
修复方案
核心是替换阻塞的启动方法,用非阻塞方式启动常驻bat,拿到进程句柄后主程序就可以继续执行后续逻辑,等业务跑完再主动终止bat进程即可,不需要额外依赖单独的终止脚本(当然如果你原有终止脚本有特殊清理逻辑也可以保留)。
基础实现
用subprocess.Popen()代替subprocess.call()启动脚本,这个方法启动子进程后会立刻返回进程对象,不会阻塞主程序:
import subprocess # 非阻塞启动bat脚本 bat_proc = subprocess.Popen( [<path_bat_file_to_run>], shell=True, # Windows环境运行bat建议开启,避免路径、环境变量识别异常 ) # 后续逻辑会立刻执行,不会等待bat退出 <other_instructions> # 业务逻辑执行完成后,终止常驻的bat进程 bat_proc.terminate() bat_proc.wait() # 回收进程资源,避免产生僵尸进程
如果terminate()无法正常终止进程,可以替换为强制杀死的bat_proc.kill()方法。
适配bat拉起多级子进程的场景
如果你的bat启动后会额外拉起其他子进程,基础的terminate()/kill()只会杀掉最外层的cmd宿主进程,残留的子进程会继续在后台运行。这种场景启动时需要加进程组标记,终止时递归杀掉整个进程树:
import subprocess # 启动时指定新建进程组 bat_proc = subprocess.Popen( [<path_bat_file_to_run>], shell=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP ) # 执行业务逻辑 <other_instructions> # 递归强制杀掉整个进程树,包括bat拉起的所有子进程 subprocess.call( ['taskkill', '/F', '/T', '/PID', str(bat_proc.pid)], shell=True )
注意事项
- 不要在启动bat后立刻调用
bat_proc.wait(),这个方法会等待子进程退出,加了之后会变回阻塞效果 - 如果bat依赖特定工作目录下的文件,可以给
Popen传入cwd="bat所在目录的绝对路径"参数,避免相对路径找不到文件的问题 - 如果你要保留原有专门用来终止bat的脚本,只需要把启动bat的
subprocess.call()换成subprocess.Popen()即可,主程序就可以正常走到后续调用终止脚本的逻辑
内容的提问来源于stack exchange,提问作者Giuseppe Boezio
相关产品推荐
相关产品推荐

