如何从subprocess.Popen()获取输出?proc.stdout.readline()阻塞,无数据显示
我想从执行 Test_Pipe.py 这个文件中获取输出,我在 Linux 上尝试了以下代码,但没有成功。
Test_Pipe.py
import time
while True :
print "Someting ..."
time.sleep(.1)
Caller.py
import subprocess as subp
import time
proc = subp.Popen(["python", "Test_Pipe.py"], stdout=subp.PIPE, stdin=subp.PIPE)
while True :
data = proc.stdout.readline() #block / wait
print data
time.sleep(.1)
那行 proc.stdout.readline()
被阻塞了,所以没有任何数据输出。
4 个回答
16
Test_Pipe.py
默认会把它的输出缓存起来,这样在 Caller.py
中的 proc
就看不到任何输出,直到子进程的缓存满了(如果缓存大小是8KB,那么大概需要一分钟才能填满 Test_Pipe.py
的输出缓存)。
如果想让输出不缓存(对于文本流来说是逐行缓存),你可以给子Python脚本传递一个 -u
标志。这样就可以实时逐行读取子进程的输出:
import sys
from subprocess import Popen, PIPE
proc = Popen([sys.executable, "-u", "Test_Pipe.py"], stdout=PIPE, bufsize=1)
for line in iter(proc.stdout.readline, b''):
print line,
proc.communicate()
有关如何解决非Python子进程的块缓存问题,请查看 Python: read streaming input from subprocess.communicate() 中的链接。
20
Nadia的代码确实可以用,但用1字节的缓冲区来调用read是不太推荐的。更好的做法是使用fcntl把标准输出的文件描述符设置为非阻塞模式。
fcntl.fcntl(
proc.stdout.fileno(),
fcntl.F_SETFL,
fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
)
然后可以用select来检查数据是否准备好了。
while proc.poll() == None:
readx = select.select([proc.stdout.fileno()], [], [])[0]
if readx:
chunk = proc.stdout.read()
print chunk
她说得对,你的问题肯定和你发的Caller.py以及Test_Pipe.py不一样,因为这两个文件按原样提供是可以正常工作的。
46
你当然可以使用subprocess.communicate这个方法,但我觉得你想要的是实时的输入和输出。
readline被阻塞了,因为这个进程可能在等你的输入。你可以通过逐个字符读取来解决这个问题,像下面这样:
import subprocess
import sys
process = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
while True:
out = process.stdout.read(1)
if out == '' and process.poll() != None:
break
if out != '':
sys.stdout.write(out)
sys.stdout.flush()