инкрементальный вывод с подпроцессом. ТРУБА

1

Я использую модуль subprocess для запуска команд из другого приложения. Я знаю, что вы можете сделать следующее

import subprocess

app = subprocess(args, stdout=subprocess.PIPE)
out, err = app.communicate()
print out

Я хотел бы, чтобы вывод отображался так, как это происходит, как предполагалось, одному большому блобу в конце. Идеи?

Теги:
subprocess
stdout

2 ответа

5
Лучший ответ

Проблема может заключаться в том, что команда, которую вы выполняете в подпроцессе, буферизует свой вывод: в этом случае в ответе Blender process.stdout.read(1) не будет возвращаться до тех пор, пока выходной буфер подпроцесса не будет заполнен, в результате чего он будет очищен, и таким образом рассматривается родительским процессом.

См. этот ответ и этот для получения дополнительной информации о том, как буферизация влияет на вещи.

Вот несколько сценариев для иллюстрации:

# spew.py
import sys
import time

for i in range(10):
    print 'Message no. %d' % i
    #sys.stdout.flush()
    time.sleep(1)

и

# runspew.py
import subprocess
import time

start = time.time()
p = subprocess.Popen(['python', 'spew.py'], stdout=subprocess.PIPE)
data = p.stdout.read(1)
print 'Elapsed time to first byte read: %.2f' % (time.time() - start)
data = p.stdout.read()
print 'Elapsed time to last byte read: %.2f' % (time.time() - start)
p.wait()

Теперь поместите оба сценария в один каталог и запустите python runspew.py. Вы увидите что-то вроде этого:

Elapsed time to first byte read: 10.05
Elapsed time to last byte read: 10.05

Теперь удалите комментарий из sys.stdout.flush() в spew.py и снова python runspew.py. Теперь вы увидите что-то вроде этого:

Elapsed time to first byte read: 0.02
Elapsed time to last byte read: 10.04

Обратите внимание, что runspew.py не изменилось: только программа, запущенная в качестве подпроцесса. Если запущенная программа не может быть запущена небуферизованной (или часто скрытой), вам придется использовать expect/unbuffer, как описано в других ответах, с которыми я связан.

2

Я сделал реализацию оболочки Python один раз, поэтому здесь код, который я использовал для запуска команд. Он отлично работал wget и nano, поэтому я думаю, что код подойдет вашим потребностям:

  process = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.STDOUT)

  while True:
    output = process.stdout.read(1)

    if output == '' and process.poll() != None:
      break

    if output != '':
      sys.stdout.write(output)
      sys.stdout.flush()

В принципе, вам нужно писать непосредственно в stdout.

  • 0
    для чего нужна полная переменная?
  • 1
    Ключ в действительности заключается в вызове sys.stdout.flush() , иначе Python продолжит буферизовать вывод.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню