Нужно избегать тупиковых ситуаций подпроцесса без связи - PullRequest
22 голосов
/ 07 апреля 2011

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

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

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

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

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

Ответы [ 5 ]

12 голосов
/ 08 апреля 2011

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()
6 голосов
/ 07 апреля 2011

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

3 голосов
/ 07 апреля 2011

Похоже, вам нужно выполнить неблокирующее чтение файловых дескрипторов, прикрепленных к каналам.

В этом вопросе рассматриваются некоторые способы сделать это для Windows и Linux: Неблокирующее чтение для подпроцесса. ТРУБА в python

1 голос
/ 08 апреля 2011

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

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

0 голосов
/ 07 апреля 2011

Вы можете рассмотреть возможность использования нескольких потоков. Назначьте один поток для чтения из 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...