Как получить информацию в режиме реального времени из подпроцесса. Открыть в python (2.5) - PullRequest
46 голосов
/ 17 мая 2009

Я бы хотел использовать модуль подпроцесса следующим образом:

  1. создать новый процесс, который потенциально может занять много времени.
  2. захват stdout (или stderr, или потенциально оба, вместе или по отдельности)
  3. Обрабатывать данные из подпроцесса по мере поступления, возможно, запускать события в каждой полученной строке (скажем, в wxPython) или просто выводить их на печать.

Я создал процессы с помощью Popen, но если я использую функцию connect (), данные сразу попадают на меня сразу после завершения процесса.

Если я создаю отдельный поток, который выполняет блокировку readline() из myprocess.stdout (используя stdout = subprocess.PIPE), я также не получу никаких строк с этим методом, пока процесс не завершится. (независимо от того, что я установил как bufsize)

Есть ли способ справиться с этим, который не является ужасным и хорошо работает на нескольких платформах?

Ответы [ 10 ]

8 голосов
/ 17 мая 2009

Обновление с кодом, который, кажется, не работает (во всяком случае, в Windows)

class ThreadWorker(threading.Thread):
    def __init__(self, callable, *args, **kwargs):
        super(ThreadWorker, self).__init__()
        self.callable = callable
        self.args = args
        self.kwargs = kwargs
        self.setDaemon(True)

    def run(self):
        try:
            self.callable(*self.args, **self.kwargs)
        except wx.PyDeadObjectError:
            pass
        except Exception, e:
            print e



if __name__ == "__main__":
    import os
    from subprocess import Popen, PIPE

    def worker(pipe):
        while True:
            line = pipe.readline()
            if line == '': break
            else: print line

    proc = Popen("python subprocess_test.py", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)

    stdout_worker = ThreadWorker(worker, proc.stdout)
    stderr_worker = ThreadWorker(worker, proc.stderr)
    stdout_worker.start()
    stderr_worker.start()
    while True: pass
7 голосов
/ 17 мая 2009

стандартный вывод будет буферизован - так что вы ничего не получите, пока этот буфер не будет заполнен или подпроцесс завершится.

Вы можете попробовать сбросить stdout из подпроцесса, либо использовать stderr, либо изменить stdout в небуферизованном режиме.

2 голосов
/ 22 декабря 2009

Вот что у меня сработало:

cmd = ["./tester_script.bash"]
p = subprocess.Popen( cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
while p.poll() is None:
    out = p.stdout.readline()
    do_something_with( out, err )

В вашем случае вы можете попытаться передать ссылку на подпроцесс в ваш рабочий поток и выполнить опрос внутри потока. Я не знаю, как он будет себя вести, когда два потока опрашивают (и взаимодействуют) один и тот же подпроцесс, но он может работать.

Также обратите внимание, что while p.poll() is None: предназначен как есть. не заменить его на while not p.poll() как в python 0 (код возврата для успешного завершения) также считается False.

2 голосов
/ 17 мая 2009

Похоже, проблема может заключаться в использовании буферизованного вывода подпроцессом - если создается относительно небольшое количество вывода, он может буферизироваться до выхода из подпроцесса. Некоторый фон можно найти здесь :

1 голос
/ 04 августа 2016

Используя subprocess.Popen, я могу запустить .exe одного из моих C # проектов и перенаправить вывод в мой файл Python. Теперь я могу print() всю информацию, выводимую на консоль C # (используя Console.WriteLine()) на консоль Python.

Код Python:

from subprocess import Popen, PIPE, STDOUT

p = Popen('ConsoleDataImporter.exe', stdout = PIPE, stderr = STDOUT, shell = True)

while True:
    line = p.stdout.readline()
    print(line)
    if not line:
        break

Получает консольный вывод моего проекта .NET построчно по мере его создания и выходит из цикла while по окончании проекта. Я полагаю, что это будет работать для двух файлов Python.

1 голос
/ 22 июня 2014

Читайте по одному символу за раз: http://blog.thelinuxkid.com/2013/06/get-python-subprocess-output-without.html

import contextlib
import subprocess

# Unix, Windows and old Macintosh end-of-line
newlines = ['\n', '\r\n', '\r']
def unbuffered(proc, stream='stdout'):
    stream = getattr(proc, stream)
    with contextlib.closing(stream):
        while True:
            out = []
            last = stream.read(1)
            # Don't loop forever
            if last == '' and proc.poll() is not None:
                break
            while last not in newlines:
                # Don't loop forever
                if last == '' and proc.poll() is not None:
                    break
                out.append(last)
                last = stream.read(1)
            out = ''.join(out)
            yield out

def example():
    cmd = ['ls', '-l', '/']
    proc = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        # Make all end-of-lines '\n'
        universal_newlines=True,
    )
    for line in unbuffered(proc):
        print line

example()
1 голос
/ 29 марта 2013

Это, кажется, хорошо известное ограничение Python, см. PEP 3145 и, возможно, другие.

1 голос
/ 18 мая 2010

Использование pexpect [http://www.noah.org/wiki/Pexpect] с неблокирующими readlines решит эту проблему. Это связано с тем, что каналы буферизуются, и поэтому выходные данные вашего приложения буферизуются каналом, поэтому вы не можете получить эти выходные данные, пока буфер не заполнится или процесс не завершится.

1 голос
/ 24 февраля 2010

Я тоже столкнулся с этой проблемой. Проблема возникает из-за того, что вы также пытаетесь читать stderr. Если ошибок нет, то попытка чтения из stderr будет блокирована.

В Windows нет простого способа опроса () файловых дескрипторов (только сокеты Winsock).

Так что решение не в том, чтобы пытаться читать с stderr.

0 голосов
/ 21 сентября 2009

Я использовал для этого модуль pexpect, похоже, он работает нормально. http://sourceforge.net/projects/pexpect/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...