2010-03-09 2 views
10

У меня есть интерактивная программа под названием my_own_exe. Сначала он печатает alive, затем вы вводите S\n, а затем снова распечатываете alive. Наконец, вы вводите L\n. Он выполняет некоторую обработку и завершает работу.Почему python.subprocess зависает после proc.communicate()?

Однако, когда я называю это из следующего сценария python, программа, похоже, зависала после распечатки первого «живого».

Может ли кто-нибудь здесь сказать мне, почему это происходит?

// после прочтения последующих взлетов (спасибо ребят), я изменил код следующим образом:

import subprocess 
import time 

base_command = "./AO_FelixStrategy_UnitTest --bats 31441 --chix 12467 --enxutp 31884 --turq 26372 --symbol SOGN --target_date " + '2009-Oct-16' 
print base_command 

proc2 = subprocess.Popen(base_command, shell=True , stdin=subprocess.PIPE,) 

time.sleep(2); 
print "aliv" 
proc2.communicate('S\n') 

print "alive" 
time.sleep(6) 

print "alive" 
print proc2.communicate('L\n') 
time.sleep(6) 

теперь программа идет хорошо с первым вводом «S \ п», но затем остановился, и I второй «L \ n» игнорируется.

Может ли кто-нибудь дать мне представление, почему это так?

ответ

23

docs for communicate От:

Взаимодействовать с процессом: Передача данных в стандартный ввод. Чтение данных из stdout и stderr, пока не будет достигнут конец файла. Подождите, пока процесс завершится.

Таким образом, после communicate() работает, этот процесс был прекращен .

Если вы хотите читать и писать, не дожидаясь процесса, чтобы остановить:

  • Не никогда использование shell=True - это needlessy вызывает оболочку в свою очередь, вызовет вашу программу, так что будет быть другим процессом между вами и вашей программой. У этого есть много неприятных побочных эффектов. Значение по умолчанию - shell=False, поэтому вы должны придерживаться этого. Изменить Popen строку:

    p = subprocess.Popen(["./AO_FelixStrategy_UnitTest", 
             "--bats", "31441", "--chix", "12467", 
             "--enxutp", "31884", "--turq", "26372", 
             "--symbol", "SOGN", "--target_date", '2009-Oct-16'], 
            stdin=subprocess.PIPE, 
            stdout=subprocess.PIPE) 
    
  • Использование p.stdin.write для записи в процессе. Используйте p.stdout.read, чтобы прочитать его.

  • Вызов p.stdout.read, если читать нечего будет заблокировано. Вызов p.stdin.write, если буфер записи заполнен, будет заблокирован. Поэтому вы должны убедиться, что у вас есть что-то читать/писать - вы делаете это в ОС Unix, используя select. В окнах вы, к сожалению, должны прибегать к потокам. По крайней мере, это то, что делает Popen.communicate.
  • Если вы не писали AO_FelixStrategy_UnitTest то у вас есть возможные дополнительные проблемы:
    • Это может быть чтение где-то еще, а не стандартный ввод. Некоторые программы читаются непосредственно с терминала, другие используют некоторый OS API для чтения. Это означает, что данные, записанные в stdin, не будут отправляться в программу. Это часто верно для подсказок пароля.
    • Помните, что вам нужно подобрать AO_FelixStrategy_UnitTest буферы.По умолчанию стандарт C PIPE связи буферном, так что вы можете не увидеть выход, пока после того, как вы закрыли на стороне входа (делая p.stdin.close(). Если AO_FelixStrategy_UnitTest не промывает выход периодически.

Вот пример кода, . на основе того, что вы описали это может работать в зависимости от того, как AO_FelixStrategy_UnitTest был разработан:

p = subprocess.Popen(["./AO_FelixStrategy_UnitTest", 
         "--bats", "31441", "--chix", "12467", 
         "--enxutp", "31884", "--turq", "26372", 
         "--symbol", "SOGN", "--target_date", '2009-Oct-16'], 
        stdin=subprocess.PIPE, 
        stdout=subprocess.PIPE) 
output = p.communicate('S\nL\n')[0] 
print output 
+0

Не перезагружается ли процесс каждый раз, когда он называет 'proc2'? Или не звонит, так как он печатает перед двумя из них? И если это так, то почему замораживание после первого отпечатка, а не второе? – Anthony

+0

@ Энтони: Нет. Процесс не восстанавливается. Он замерзает после первой печати, потому что «сообщение» ожидает завершения процесса, но процесс никогда не заканчивается, потому что он, вероятно, застревает во втором приглашении (тот, где нужно ввести «L \ n''). – nosklo

+0

спасибо. во всяком случае, это только частично решает проблему, я могу использовать общаться только один раз, правильно? если мне нужно ИНТЕРАКТИВНО читать и писать, читать и писать, этот «output = p.communicate (« S \ nL \ n ») [0]« не может работать, правильно? –

3

communicate() читает данные на стандартный вывод и стандартный поток ошибок до конца из-файла достигается - Он ждет. пока ваша программа не завершится.

+0

Итак, какой правильный метод для обратного взаимодействия с подпроцессом? – Anthony

+0

@ Anthony: Правильный способ - использовать 'p.stdin.write()' и 'p.stdout.read()'. Однако они могут блокироваться, поэтому вы используете 'select()' в unix или потоках в окнах, чтобы избежать блокировки Проверьте, что '.communicate()' делает, проверяя исходный код 'subprocess.py'. Проверьте мой ответ для получения более подробной информации. – nosklo

+0

Это был не мой вопрос, я просто пытался сгенерировать что-то, что SO могло бы найти полезным для исправления его кода. Это и я искренне любопытно, поскольку в прошлые выходные я работал над чем-то смутно похожим на PHP, и мне нравится знать, как живет лучшая половина. – Anthony

0

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

Вот пример, который работал для меня после того, как исследование, пытаясь резьб, subprocess32, stdin.write, stdout.read и т.д. и т.п. Эта информация не является официальной справочной питон информации для общения: https://docs.python.org/2/library/subprocess.html

только место, где я нашел это здесь: Python subprocess communicate kills my process

В любом случае здесь приведен код, простой, без потоков, без подпроцесса32, работает на linux и windows. Да, вы должны знать, сколько раз отправлять команды другому процессу, но в целом вы это знаете. Помимо этого вы можете добавлять потоки, УХО, оболочки = True или что-либо еще вы можете, но это самый простой случай:

def do_commands(self, cmd, parms): 
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) 

    # wait for the process to terminate 
    out, err = process.communicate(cmd_parms) 
    errcode = process.returncode 

    return errcode, out, err 

Так, например, если вы хотите отправить несколько возврата каретки (\ п) к вызываемое приложение и a param в середине (в интерактивном режиме) вы назовете это примерно так:

cmd_parms = "\n\n\n\n\nparm\n\n" 

errcode, out, err = do_commands(command, cmd_parms) 
Смежные вопросы