Python:如何非阻塞地读取另一个进程的stdout?

12 投票
3 回答
17624 浏览
提问于 2025-04-16 19:55

在一个程序运行的时候,我想要读取它的标准输出(stdout),然后把这些内容写入一个文件。不过我尝试了很多方法,结果都是一尝试读取标准输出,程序就卡住,直到它运行完毕。

下面是我正在尝试的代码片段。(第一部分只是一个简单的Python脚本,它会向标准输出写入一些内容。)

import subprocess

p = subprocess.Popen('python -c \'\
from time import sleep\n\
for i in range(3):\n\
    sleep(1)\n\
    print "Hello", i\
\'', shell = True, stdout = subprocess.PIPE)

while p.poll() == None:
    #read the stdout continuously
    pass

print "Done"

我知道网上有很多问题讨论的是同样的主题。但是,我找到的那些问题都没有办法解决我的困惑。

3 个回答

-3

你可以使用 subprocess.communicate() 来获取标准输出(stdout)中的内容。可以这样做:

while(p.poll() == None):
    #read the stdout continuously
    print(p.communicate()[0])
    pass

更多信息可以在这里找到: http://docs.python.org/library/subprocess.html

5

下面的代码会在子进程运行时,逐行打印标准输出,直到readline()方法返回一个空字符串为止:

p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''):
    print line
p.stdout.close()
print 'Done'

更新一下,更好地与您的问题相关:

import subprocess

p = subprocess.Popen(['python'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
p.stdin.write("""
from time import sleep ; import sys
for i in range(3):
    sleep(1)
    print "Hello", i
    sys.stdout.flush()
""")
p.stdin.close()
for line in iter(p.stdout.readline, ''):
    print line
p.stdout.close()
print 'Done'
12

发生的事情是写入端的缓冲。因为你从那段小代码中写入的数据块很小,所以底层的文件对象会把输出先缓存在内存里,直到结束时才一起写出去。下面的代码就能按你预期的那样工作。

#!/usr/bin/python

import sys
import subprocess

p = subprocess.Popen("""python -c '
from time import sleep ; import sys
for i in range(3):
    sleep(1)
    print "Hello", i
    sys.stdout.flush()
'""", shell = True, stdout = subprocess.PIPE)

while True:
    inline = p.stdout.readline()
    if not inline:
        break
    sys.stdout.write(inline)
    sys.stdout.flush()

print "Done"

不过,你可能对这个情况没有预期到。缓冲的目的是为了减少系统调用的次数,从而让系统运行得更高效。你真的在意整个文本在写入文件之前都被缓存在内存里吗?你不还是能在文件里看到所有的输出吗?

撰写回答