Python: Как читать стандартный вывод подпроцесса неблокирующим способом

Я пытаюсь сделать простой скрипт на Python, который запускает подпроцесс и отслеживает его стандартный вывод. Вот фрагмент кода:

process = subprocess.Popen([path_to_exe, os.path.join(temp_dir,temp_file)], stdout=subprocess.PIPE)
while True:   
    output=process.stdout.readline()
    print "test"

Проблема в том, что скрипт висит на output=process.stdout.readline() и что линия print "test" выполняется только после завершения подпроцесса.

Есть ли способ прочитать стандартный вывод и распечатать его, не дожидаясь завершения подпроцесса?

Подпроцесс, который я запускаю, является двоичным файлом Windows, для которого у меня нет исходного кода.

Я нашел несколько похожих вопросов, но ответы применимы только к Linux или в случае, если у меня есть источник суперпроцесса, который я запускаю.

3 ответа

Решение

Проверьте выбранный модуль

import subprocess
import select
import time

x=subprocess.Popen(['/bin/bash','-c',"while true; do sleep 5; echo yes; done"],stdout=subprocess.PIPE)

y=select.poll()
y.register(x.stdout,select.POLLIN)

while True:
  if y.poll(1):
     print x.stdout.readline()
  else:
     print "nothing here"
     time.sleep(1)

РЕДАКТИРОВАТЬ:

Резьбовое решение для не posix систем:

import subprocess
from threading import Thread 
import time

linebuffer=[]
x=subprocess.Popen(['/bin/bash','-c',"while true; do sleep 5; echo yes; done"],stdout=subprocess.PIPE)

def reader(f,buffer):
   while True:
     line=f.readline()
     if line:
        buffer.append(line)
     else:
        break

t=Thread(target=reader,args=(x.stdout,linebuffer))
t.daemon=True
t.start()

while True:
  if linebuffer:
     print linebuffer.pop()
  else:
     print "nothing here"
     time.sleep(1)

Начиная с python 3.5 вы можете использовать следующее.

      import os
import subprocess

process = subprocess.Popen([path_to_exe, os.path.join(temp_dir,temp_file)], stdout=subprocess.PIPE)
os.set_blocking(process.stdout.fileno(), False) #<----- HERE
while True:   
    output=process.stdout.readline()
    print "test"


    if process.poll() is not None:
        break
rc = process.poll()

Обратите внимание , чтоos.set_blocking()доступен только на платформах UNIX.

Вы можете попробовать это:

import subprocess
import os

""" Continuously print command output """
""" Will only work if there are newline characters in the output. """

def run_cmd(command):    
    popen = subprocess.Popen(command, stdout=subprocess.PIPE)
    return iter(popen.stdout.readline, b"")

for line in run_cmd([path_to_exe, os.path.join(temp_dir,temp_file)]):
    print(line), # the comma keeps python from adding an empty line
Другие вопросы по тегам