Если вы напишите
for line in p.stdout:
, то вы (вроде) неявно скажете, что хотите дождаться полной строки
, вам пришлось использовать read(num_bytes)
, а не readline()
Ниже приведен один пример для иллюстрации:
sub.py : (пример подпроцесса)
import sys, time
for v in range(20):
print(".", end="")
sys.stdout.flush()
if v % 4 == 0:
print()
if v % 3 != 0:
time.sleep(0.5)
rdunbuf.py : (пример чтения stddout без буферизации)
contextlib, time, subprocess
def unbuffered(proc, stream='stdout'):
stream = getattr(proc, stream)
with contextlib.closing(stream):
while True:
last = stream.read(80) # read up to 80 chars
# stop when end of stream reached
if not last:
if proc.poll() is not None:
break
else:
yield last
# open subprocess without buffering and without universal_newlines=True
proc = subprocess.Popen(["./sub.py"], stdout=subprocess.PIPE, bufsize=0)
for l in unbuffered(proc):
print(l)
print("end")
Обратите также внимание, что ваш код может блокироваться, если он выдает много сообщений об ошибках перед выдачей нормального вывода, так как вы сначала пытаетесь прочитать все нормальные выходные данные и только тогда данные из stderr.
Вы должны читать все данные, которые ваш подпроцесс производит, как прежде, чем любые конвейерные буферы блокируют независимо, будь то stdout или stderr. Вы можете использовать select.select()
(https://docs.python.org/3.8/library/select.html#select .select ), чтобы решить, нужно ли вам читать с stdout или с stderr