【问题标题】:Why is piping output of subprocess so unreliable with Python?为什么使用 Python 的子进程的管道输出如此不可靠?
【发布时间】:2012-04-14 01:58:03
【问题描述】:

(Windows)

我编写了一些调用程序 SoX(子进程模块)的 Python 代码,如果您指定它,它会输出 STDERR 上的进度。我想从输出中获取百分比状态。如果我不是从 Python 脚本调用它,它会立即启动,并且会平稳地进行到 100%。

如果我从 Python 脚本调用它,它会持续几秒钟直到它开始,然后它会在慢速输出和快速输出之间交替。尽管我有时会逐个字符地读取字符,但有时会冲出一大块。所以我不明白为什么在其他时候我可以看到角色一个接一个地变多。 (顺便说一下,它在我的测试中生成了 15KiB 的数据。)

我已经对 mkvmerge 和 mkvextract 进行了同样的测试。他们也输出百分比。在那里读取 STDOUT 很流畅。

这太不靠谱了!如何让 sox 的 stderr 流的读取更流畅,或许还能防止一开始的延迟?


我如何打电话和阅读:

process = subprocess.Popen('sox_call_dummy.bat', stderr = subprocess.PIPE, stdout = subprocess.PIPE)
while True:
    char = process.stderr.read(1).encode('string-escape')
    sys.stdout.write(char)

【问题讨论】:

  • 你的 bufsize 值是多少?你能展示你的子进程sn-p吗?
  • 零(默认)。但是我刚刚测试了1、1024、8*1024、16*1024、160*1024,每个值都是一样的。
  • 发布一个代码示例,说明您如何调用和读取您的流程。
  • 可能你需要禁用缓冲。

标签: python performance subprocess pipe piping


【解决方案1】:

根据这个密切相关的线程:Unbuffered read from process using subprocess in Python

process = subprocess.Popen('sox_call_dummy.bat', 
                stderr = subprocess.PIPE, bufsize=0)
while True:
    line = process.stderr.readline()
    if not line: 
        break
    print line

由于您没有阅读标准输出,我认为您不需要管道。

如果您想像原始示例一样尝试逐个字符地读取字符,请尝试每次都添加一个刷新:

sys.stdout.write(char)
sys.stdout.flush()

每次写入时刷新标准输出相当于为 python 进程禁用缓冲:python.exe -u <script> 或设置 env 变量 PYTHONUNBUFFERED=1

【讨论】:

  • 如果没有控制台窗口但有一个空闲的 GUI 窗口,我尝试运行脚本时出现错误,因此我为 stdout 创建了一个管道。
  • @rynd:好吧,如果有东西正在阅读,那么一定要把它加回来。
  • 问题依然存在。如果我查看子进程的 CPU 负载,我看到 sox 正在处理 90% 的负载,而我的脚本仍然有延迟。为什么 read() 在这一点上不起作用?然后第一个输出(与进度无关的信息)慢慢输出。
  • @rynd:flush 对你的 write() 没有帮助吗?
  • @rynd:可能是特定于 Windows 的。您可以尝试对子进程缓冲输出和窗口进行一些搜索。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-11
  • 2011-06-18
  • 1970-01-01
  • 2012-06-18
  • 2017-01-12
相关资源
最近更新 更多