[英]Non-blocking read on subprocess PIPE in Python, one byte at a time
我在這個問題的代碼上實現了一個變體:
Python 中 subprocess.PIPE 的非阻塞讀取
要嘗試從這個虛擬程序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!"
另一個問題的變化是調用程序必須逐個字符而不是逐行讀取,因為虛擬程序test.py
使用\\r
在一行上輸出進度指示。 所以這里是:
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)
這有兩個問題
p.returncode
永遠不會返回值,並且不會留下循環。 我該如何解決?buffersize
情況下提高效率?正如@Markku K. 指出的那樣,您應該使用bufsize=0
讀取一個字節。
您的代碼不需要非阻塞讀取。 你可以簡化它:
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()
注意:一次讀取 1 個字節是非常低效的。
此外,通常可能存在塊緩沖問題,有時可以使用pexpect
、 pty
模塊或unbuffer
、 stdbuf
、 script
命令行實用程序來解決。
對於 Python 進程,您可以使用-u
標志來強制對 stdin、stdout、stderr 流進行非緩沖(二進制層)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.