Подтвердить что ты не робот

Необходимо избегать взаимоблокировки подпроцесса без связи

Мне нужно выполнить команду, которая производит много результатов и занимает много времени для выполнения ( > 30 минут). Я думал об использовании подпроцесса. Приобрести это. Мне нужно захватить вывод команды, поэтому я передаю PIPE в stdout и stderr.

Проблема взаимоблокировки при использовании Popen.wait() хорошо документирована на многих форумах, поэтому Popen.communicate() - это предлагаемый способ избежать тупика. Проблема с этим решением заключается в том, что связь() блокируется до тех пор, пока команда не будет завершена. Мне нужно напечатать все, что приходит на stdout во время выполнения команды. Если после 20 минут выхода нет, выполнение script будет убито.

Вот некоторые ограничения, которые мне нужно соблюдать:

  • Моя версия Python - 2.4.2, и я не могу выполнить обновление.
  • Если решение по-прежнему будет использовать подпроцесс, мне нужно передать subprocess.PIPE во все дескрипторы std, чтобы избежать этой ошибки: http://bugs.python.org/issue1124861

Есть ли способ сделать это?

4b9b3361

Ответ 1

import os
from subprocess import PIPE, STDOUT, Popen

lines = []
p = Popen(cmd, bufsize=1, stdin=open(os.devnull), stdout=PIPE, stderr=STDOUT)
for line in iter(p.stdout.readline, ''):
      print line,          # print to stdout immediately
      lines.append(line)   # capture for later
p.stdout.close()
p.wait()

Ответ 2

Вы пробовали pexpect?

Ответ 4

Чтобы избежать заполнения буферов, просто запустите фоновый поток в родительском процессе. Этот поток может либо просто непрерывно считываться из stdout (и stderr), чтобы не допустить заполнения буферов каналов, либо вы можете вызывать communicate() из него. В любом случае, основной поток можно продолжить с обычной обработкой, и дочерний процесс не будет блокировать операцию вывода.

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

Ответ 5

Вы можете использовать несколько потоков. Назначьте один поток для чтения из stdout, один из stderr и используйте третий поток для обнаружения таймаута:

while time.time() - last_output_time < 20 * 60:
    time.sleep( 20 * 60 - (time.time() - last_output_time) )
print 'No output detected in the last 20 minutes. Terminating execution'
sys.exit(1)