2009-07-10 3 views
4

Я хотел бы иметь возможность запускать процесс в python и иметь двухстороннюю связь. Конечно, Pexpect делает это, и я действительно могу пойти. Однако это не совсем идеально.Вопрос подпроцесса Python

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

Посмотрите на документацию, он говорит, что есть дескрипторы файлов stdin, stdout и stderr, с которыми я могу напрямую манипулировать, но есть большое толстое предупреждение, в котором говорится: «Do not Do This». К сожалению, не совсем понятно, почему это предупреждение существует, но из того, что я собираю из google, является то, что оно связано с буферизацией os, и можно написать код, который неожиданно блокирует, когда эти внутренние буферы терпят неудачу (в качестве примечания стороны, любые примеры, которые показать неправильный путь, и правильный путь был бы оценен).

Так что, рискуя своим кодом для потенциальных тупиков, я подумал, что было бы интересно использовать опрос или выбрать интерактивное чтение из работающего процесса, не убивая его. Хотя я теряю (я думаю) кросс-платформенную способность, мне нравится тот факт, что он не требует дополнительных библиотек. Но что более важно, я хотел бы знать, действительно ли это хорошая идея. Мне еще предстоит попробовать этот подход, но я обеспокоен ошибками, которые могут привести к разрушению моей программы. Может ли это работать? Что я должен проверить?

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

+0

Argh! Все мои надежды и мечты, казалось, были подавлены буферизацией stdout!Почему Wont операционная система просто дать мне эти бит: < – Voltaire

+0

вы вызываете некоторые внешние сторонние инструменты, для которых у Python нет модуля/библиотеки? – ghostdog74

+0

В некотором смысле, да. К счастью, они находятся под моим контролем, поэтому у меня есть определенная гибкость в моем решении. Если вызываемый скрипт сбрасывает stdout, я могу работать с ним в интерактивном режиме. В идеале, я хотел бы сделать stdout небуферизованным потоком, но это кажется невозможным. – Voltaire

ответ

0

Короткий ответ заключается в том, что для управления процессами не существует хорошей системы перекрестной платформы, не конструируя эту концепцию в вашей системе. Это особенно в стандартных библиотеках. Даже различные версии unix имеют свои проблемы с совместимостью.

Лучше всего использовать все процессы с надлежащей обработкой событий, чтобы заметить события, которые происходят из любой системы IPC, наилучшим образом работающей на любой платформе. Именованные трубы будут основным маршрутом для описанной вами проблемы, но на каждой платформе будут реализованы различия .

3

Используйте модуль multiprocessing в стандартной библиотеке Python 2.6.

У этого есть Queue class, который может использоваться как для чтения, так и для записи.

+0

Я поддержал это, недавно создав проект, основанный на этом модуле. Есть несколько ошибок, хотя, если вы делаете кросс-платформенный dev, например, отсутствие вилки в Windows, что, в свою очередь, означает, что это эмулируется в Python с некоторыми нечетными побочными эффектами. Однако, как заявил плакат, он дает вам приятные пушистые способы общения с вашим детским процессом и делает вещи очень легкими в целом. – jkp

1

Я делаю это в отдельном потоке, используя очереди сообщений для связи между потоками. В моем случае подпроцесс печатает% complete в stdout. Я хотел, чтобы основной поток поднял хороший индикатор выполнения.

if sys.platform == 'win32': 
     self.shell = False 
     self.startupinfo = subprocess.STARTUPINFO() 
     self.startupinfo.dwFlags = 0x01 
     self.startupinfo.wShowWindow = 0 
    else: 
     self.shell = True 
     self.startupinfo = None 

. . .

f = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, env = env, shell = self.shell, startupinfo = self.startupinfo) 
    f.stdin.close() 
    line = '' 
    while True: 
     log.debug('reading') 
     c = f.stdout.read(1) 

     log.debug(c) 

     if len(c) == 0: 
      log.info('stdout empty; must be done') 
      break; 
     if ord(c) == 13: 
      continue 
     if c == '%': 
      # post % complete message to waiting thread. 
      line = '' 
     else: 
      line += c 


    log.info('checking for errors') 
    errs = f.stderr.readlines() 

    if errs: 
     prettyErrs = 'Reported Errors: ' 
     for i in errs: 
      prettyErrs += i.rstrip('\n') 

     log.warn(prettyErrs) 
     #post errors to waiting thread 
    else: 
     print 'done'   
    return 
+0

Я работал над этим в выходные, и это близко к решению, которое я придумал. Это не имеет никакого отношения к опросу для готовых данных, и все, что нужно сделать, поскольку stdio является буферизованным потоком. В моем конкретном случае я могу уйти с предположением, что stdout будет регулярно очищаться исполняемым скриптом. Поэтому простая блокирующая строка чтения, работающая в отдельном потоке, делает все, что мне нужно. Если у кого-то есть пример использования unbuffer stdio, я был бы очень заинтересован. – Voltaire

+0

er, by stdio Я имею в виду stdout – Voltaire