Python subprocess 子进程实时获取输出详解
本文介绍如何使用Python的subprocess模块在父进程中实时获取子进程的标准输出。通过示例演示了因缓冲区导致输出延迟的问题,并给出通过手动刷新缓冲区(flush)实现逐行实时读取的完整代码方案。
Python subprocess 模块简介
在某些系统整合场景中,我们需要将特定程序放入子进程中运行。Python 提供了 subprocess 模块,该模块为创建子进程并执行子程序提供了统一且便捷的接口。
为了在主进程中实时掌握子程序的执行进度,我们需要实时获取其输出信息。subprocess 模块提供了相关参数,允许将子程序的标准输出(stdout)和标准错误(stderr)重定向回主程序。
实时获取子进程输出的示例
下面通过一个具体示例来演示该功能。首先,我们需要编写一个用于模拟标准输出和标准错误输出的“子程序”——subprogram.py:
import sys
import time
for i in range(5):
sys.stdout.write('Processing {}\n'.format(i))
time.sleep(1)
for i in range(5):
sys.stderr.write('Error {}\n'.format(i))
time.sleep(1)
该程序逻辑简单,分别向标准输出和标准错误写入5条信息,且每条信息输出间隔1秒。接着是驱动该“子程序”运行的“主程序”——main.py:
import shlex
import subprocess
if __name__ == '__main__':
shell_cmd = 'python3 subprogram.py'
cmd = shlex.split(shell_cmd)
p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while p.poll() is None:
line = p.stdout.readline()
line = line.strip()
if line:
print('Subprogram output: [{}]'.format(line))
if p.returncode == 0:
print('Subprogram success')
else:
print('Subprogram failed')
输出延迟问题与缓冲区机制
在主程序中,我们通过设置 stderr=subprocess.STDOUT 将子程序的标准错误重定向到标准输出,从而可以直接从标准输出中同时获取这两类信息。运行该程序后,预期结果是 main.py 每秒向控制台输出一条信息,但实际现象是等待10秒后一次性显示所有10条输出。
造成这种现象的原因是标准输出和标准错误存在缓冲区机制。系统不会立即返回程序的标准输出内容,而是进行缓存,直到缓冲区满或程序结束强制清空缓存时才进行输出。明确原因后,解决方法也很直接:在子程序中,每次输出后手动清空缓冲区。以下是修改后的 subprogram.py:
import sys
import time
for i in range(5):
sys.stdout.write('Processing {}\n'.format(i))
sys.stdout.flush()
time.sleep(1)
for i in range(5):
sys.stderr.write('Error {}\n'.format(i))
sys.stderr.flush()
time.sleep(1)
解决方案与测试结果
经过上述修改后,再次运行 main.py 程序,可以看到每秒输出一条信息,成功实现了在主程序中追踪子程序执行过程的目标。
注:测试环境为 Python3.6.1 Mac 版。
以上关于 Python 从 subprocess 运行的子进程中实时获取输出的示例内容到此结束,希望能对大家有所帮助。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













