用于流式传输的subprocess.Popen.communicate()的替代方案

时间:2017-02-09 22:31:08

标签: python io subprocess

如果我正在使用subprocess.Popen,我可以将communicate()用于小输出。

但如果子流程需要大量时间并产生大量输出,我想将其作为流数据访问。

有办法做到这一点吗? Python文档说

  

警告:使用communicate()而不是.stdin.write.stdout.read.stderr.read,以避免因任何其他操作系统管道缓冲区填满并阻止子进程而导致死锁。

我真的想将进程输出作为类文件对象访问:

with someMagicFunction(['path/to/some/command','arg1','arg2','arg3']) as outpipe:
   # pass outpipe into some other function that takes a file-like object

但无法弄清楚如何做到这一点。

1 个答案:

答案 0 :(得分:1)

communicate是一种方便的方法,可以启动后台线程来阅读stdoutstderr。您可以自己阅读stdout,但是您需要弄清楚如何处理stderr。如果您不关心错误,可以将参数stderr=open(os.devnull, 'wb')添加到文件stderr=open('somefile', 'wb')。或者,创建自己的后台线程来进行读取。事实证明shutil已经有了这样的功能,所以我们可以使用它。

import subprocess
import threading
import shutil
import io

err_buf = io.BytesIO()

proc = subprocess.Popen(['ls', '-l'],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
err_thread = threading.Thread(target=shutil.copyfileobj, 
    args=(proc.stderr, err_buf))
err_thread.start()
for line in proc.stdout:
    print(line.decode('utf-8'), end='')
retval = proc.wait()
err_thread.join()
print('error:', err_buf.getvalue())