Получение сообщения о прогрессе из подпроцесса - PullRequest
19 голосов
/ 10 февраля 2011

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

Единственная функция, которую я нашел для считывания вывода программы, - Popen.communicate(), но этот метод ожидает, пока процесс не завершится,Таким образом, невозможно получить прогресс и сделать его видимым для пользователя в специальном формате.

Можно ли сделать это по-другому?

Когда я запускаю процесс с subprocess.popen своим скриптом я вижу вывод программы на экран.Можно ли это скрыть?(Ubuntu 10.10, обычный терминал)

Ответы [ 3 ]

19 голосов
/ 10 февраля 2011

Проще всего позвонить Попену с ключевым словом аргумент stdout=subprocess.PIPE.

p = subprocess.Popen(["ls"], stdout=subprocess.PIPE)
while True:
    line = p.stdout.readline()
    if not line:
        break
    print line

Чтобы увидеть это в действии, вот два примера сценария. Сделайте их обоих в одном каталоге и запустите python superprint.py

printandwait.py:

import time
import sys
print 10
sys.stdout.flush()
time.sleep(10)
print 20
sys.stdout.flush()

superprint.py:

import subprocess
import sys
p = subprocess.Popen(["python printandwait.py"], shell=True, stdout=subprocess.PIPE)
while True:
    print "Looping"
    line = p.stdout.readline()
    if not line:
        break
    print line.strip()
    sys.stdout.flush()
2 голосов
/ 10 февраля 2011

Вы можете сделать опрос о состоянии вашего подпроцесса и продолжать выводить строки.

p = subprocess.Popen('ls;sleep 10', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

rc = p.poll()
while rc != 0:
    while True:
        line = p.stdout.readline()
        if not line:
            break
        print line
    rc = p.poll()

assert rc == 0
1 голос
/ 10 февраля 2011

Это, безусловно, возможно: мой пакет python-gnupg делает именно это, порождая gpg (Gnu Privacy Guard) в рамках подпроцесса.В общем случае вам нужно указать subprocess.PIPE для подпроцесса stdout и stderr;затем создайте два отдельных потока, которые читают подпроцесс stdout и stderr в любое удобное для вас место.

В случае python-gnupg сообщения о состоянии от gpg читаются и обрабатываются во время выполнения процесса gpg (неожидание, пока оно не закончится).

По сути, псевдокод равен

process = subprocess.Popen(..., stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stderr = process.stderr
rr = threading.Thread(target=response_reader_func, args=(process.stderr,))
rr.setDaemon(True)
rr.start()

dr = threading.Thread(target=data_reader_func, args=(process.stdout,))
dr.setDaemon(True)
dr.start()

dr.join()
rr.join()
process.wait()

Функции считывателя обычно представляют собой методы включающего класса, которые делают правильные вещи в зависимости от того, что они читаютслучай, обновление информации о прогрессе в некотором роде).

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