Python调用Perl作为subprocess 如何等待其后台进程结束并打印输出
问题原因
你原来的代码不生效是两个独立问题导致的:
- Perl脚本中
system("something &")启动的后台进程是Perl主进程的子进程,Perl主进程退出后这些进程会变成孤儿进程被系统接管,Python的subprocess.Popen默认只会等待直接启动的Perl主进程退出,不会跟踪孤儿进程的状态。 - 实时打印不生效是因为默认情况下输出会攒在进程的输出缓冲区里,只有缓冲区满或者进程退出时才会批量输出,没有主动刷新的话就看不到实时输出。
解决方案
方案1:修改Perl脚本(侵入式改法,可靠性最高)
如果允许调整Perl脚本,该方案实现最简单、性能损耗最小:
- 在Perl脚本开头添加关闭输出缓冲的配置,让输出实时刷新:
$| = 1;
- 在Perl脚本末尾添加
wait;语句,让Perl主进程等待所有自身启动的后台子进程全部退出后再结束,此时Python侧的communicate()就可以正常等待所有任务执行完成。
方案2:不修改Perl脚本,Python侧兼容处理
如果无法修改Perl脚本,可以通过shell封装调用来实现等待所有后台进程,同时逐行读取输出实现实时打印:
import subprocess import sys # 用bash封装执行逻辑:先运行Perl脚本,再调用wait等待同会话下所有后台进程退出 shell_cmd = ''' perl script.pl data1 data2 wait ''' proc = subprocess.Popen( ["bash", "-c", shell_cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # 不需要分开处理错误输出的话,可合并到标准输出 text=True, bufsize=1 # 开启行缓冲,避免输出攒批量 ) # 逐行读取输出并实时打印 for line in iter(proc.stdout.readline, ""): sys.stdout.write(line) sys.stdout.flush() # 等待进程完全退出,可根据返回码判断执行结果 return_code = proc.wait()
特殊场景优化
如果Perl脚本内部启动的后台进程本身开启了全缓冲,导致输出还是无法实时打印,可以在启动后台进程时通过stdbuf工具强制行缓冲,将Perl中的system("something &")调整为system("stdbuf -oL something &")即可。
内容的提问来源于stack exchange,提问作者Martin Perry
相关产品推荐
相关产品推荐

