[英]Non-blocking read on subprocess PIPE in Python, one byte at a time
I have implemented a variant on the code in this question:我在这个问题的代码上实现了一个变体:
A non-blocking read on a subprocess.PIPE in Python Python 中 subprocess.PIPE 的非阻塞读取
To try and read the output in real time from this dummy program test.py
:要尝试从这个虚拟程序
test.py
实时读取输出:
import time, sys
print "Hello there"
for i in range(100):
time.sleep(0.1)
sys.stdout.write("\r%d"%i)
sys.stdout.flush()
print
print "Go now or I shall taunt you once again!"
The variation on the other question is that the calling program must read character by character, not line by line, as the dummy program test.py
outputs progress indication all on one line by use of \\r
.另一个问题的变化是调用程序必须逐个字符而不是逐行读取,因为虚拟程序
test.py
使用\\r
在一行上输出进度指示。 So here it is:所以这里是:
import sys,time
from subprocess import PIPE, Popen
from threading import Thread
try:
from Queue import Queue, Empty
except ImportError:
from queue import Queue, Empty # Python 3.x
ON_POSIX = 'posix' in sys.builtin_module_names
def enqueue_output(out, queue):
while True:
buffersize = 1
data = out.read(buffersize)
if not data:
break
queue.put(data)
out.close()
p = Popen(sys.executable + " test.py", stdout=PIPE, bufsize=1, close_fds=ON_POSIX)
q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.daemon = True # Thread dies with the program
t.start()
while True:
p.poll()
if p.returncode:
break
# Read line without blocking
try:
char = q.get_nowait()
time.sleep(0.1)
except Empty:
pass
else: # Got line
sys.stdout.write(char)
sys.stdout.flush()
print "left loop"
sys.exit(0)
Two problems with this这有两个问题
p.returncode
never returns a value and the loop is not left.p.returncode
永远不会返回值,并且不会留下循环。 How can I fix it?buffersize
?buffersize
情况下提高效率?As @Markku K. pointed out, you should use bufsize=0
to read one byte at a time.正如@Markku K. 指出的那样,您应该使用
bufsize=0
读取一个字节。
Your code doesn't require a non-blocking read.您的代码不需要非阻塞读取。 You can simplify it:
你可以简化它:
import sys
from functools import partial
from subprocess import Popen, PIPE
p = Popen([sys.executable, "test.py"], stdout=PIPE, bufsize=0)
for b in iter(partial(p.stdout.read, 1), b""):
print b # it should print as soon as `sys.stdout.flush()` is called
# in the test.py
p.stdout.close()
p.wait()
Note: reading 1 byte at a time is very inefficient.注意:一次读取 1 个字节是非常低效的。
Also, in general, there could be a block-buffering issue that sometimes can be solved using pexpect
, pty
modules or unbuffer
, stdbuf
, script
command-line utilities .此外,通常可能存在块缓冲问题,有时可以使用
pexpect
、 pty
模块或unbuffer
、 stdbuf
、 script
命令行实用程序来解决。
For Python processes you could use -u
flag to force unbuffering (binary layer) of stdin, stdout, stderr streams.对于 Python 进程,您可以使用
-u
标志来强制对 stdin、stdout、stderr 流进行非缓冲(二进制层)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.