2013-05-27 3 views
43

У меня есть сценарий, названный 1st.py, который создает REPL (чтение Eval-печать с обратной связью):Понимание Popen.communicate

print "Something to print" 
while True: 
    r = raw_input() 
    if r == 'n': 
     print "exiting" 
     break 
    else: 
     print "continuing" 

Затем я начал 1st.py со следующим кодом:

p = subprocess.Popen(["python","1st.py"], stdin=PIPE, stdout=PIPE) 

А потом попытался это:

print p.communicate()[0] 

это не удалось, обеспечивая этот отслеживающий:

Traceback (most recent call last): 
    File "1st.py", line 3, in <module> 
    r = raw_input() 
EOFError: EOF when reading a line 

Не могли бы вы объяснить, что здесь происходит, пожалуйста? Когда я использую p.stdout.read(), он висит навсегда.

ответ

35

.communicate() пишет ввод (в этом случае вход не вводится, поэтому он просто закрывает подпроцесс 'stdin, чтобы указать подпроцессу, что больше нет ввода), считывает все выходные данные и ждет выхода из подпроцесса.

Исключение EOFError возникает в дочернем процессе на raw_input() (он ожидал данных, но получил EOF (без данных)).

p.stdout.read() висит навсегда, потому что он пытается прочитать все вывода ребенка в то же время, как ребенок ожидает ввода (raw_input()), что приводит к тупиковой ситуации.

Чтобы избежать тупиковой ситуации, что нужно для чтения/записи в асинхронном режиме (например, с помощью темы или выбрать) или точно знать, когда и сколько для чтения/записи, for example:

from subprocess import PIPE, Popen 

p = Popen(["python", "-u", "1st.py"], stdin=PIPE, stdout=PIPE, bufsize=1) 
print p.stdout.readline(), # read the first line 
for i in range(10): # repeat several times to show that it works 
    print >>p.stdin, i # write input 
    p.stdin.flush() # not necessary in this case 
    print p.stdout.readline(), # read output 

print p.communicate("n\n")[0], # signal the child to exit, 
           # read the rest of the output, 
           # wait for the child to exit 

Примечание: это очень хрупкий код, если чтение/запись не синхронизированы; это тупики.

Опасайтесь block-buffering issue (здесь решается, используя "-u" flag that turns off buffering for stdin, stdout in the child).

bufsize=1 makes the pipes line-buffered on the parent side.

+0

Не могли бы вы рассказать мне, в чем разница между print >> p.stdin, i и p.stdin.write (i) –

+0

здесь 'print' is' p.stdin.write (str (i) + "\ n"); p.stdin.flush() '. – jfs

+0

спасибо ... Еще одна вещь, пожалуйста, скажите мне, что это bufsize = 1 делает? Также «-u» в Popen ([«python», «-u», «1st.py»], stdin = PIPE, stdout = PIPE, bufsize = 1) –

0

Ваш второй бит кода запускает первый бит кода в качестве подпроцесса с канальным вводом и выводом. Затем он закрывает свой вход и пытается прочитать его вывод.

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

+0

спасибо ... но я просто не хочу закрывать вход. Я хочу печатать везде, где 1st.py печатает на своем выводе. Позже я сделаю p.stdin.write («Somthing to input»), а затем p.communicate() [0], чтобы напечатать это во втором коде. Вы можете мне помочь? Я просто не хочу закрывать ввод или вывод. Я новичок, поэтому, не колеблясь, поправьте меня. спасибо –

16

Не использовать связь (input = ""). Он записывает ввод в процесс, закрывает свой stdin и затем считывает весь вывод.

Делают это так:

p=subprocess.Popen(["python","1st.py"],stdin=PIPE,stdout=PIPE) 

# get output from process "Something to print" 
one_line_output = p.stdout.readline() 

# write 'a line\n' to the process 
p.stdin.write('a line\n') 

# get output from process "not time to break" 
one_line_output = p.stdout.readline() 

# write "n\n" to that process for if r=='n': 
p.stdin.write('n\n') 

# read the last output from the process "Exiting" 
one_line_output = p.stdout.readline() 

Что вы могли бы сделать, чтобы устранить ошибку:

all_the_process_will_tell_you = p.communicate('all you will ever say to this process\nn\n')[0] 

Но так как общаться закрывает stdout и stdin и stderr, вы не можете читать или писать после того, как вы вызвали общение.

+0

спасибо за ответ .. но вы можете видеть, что моя первая программа ждет ввода пользователя и до этого печатает «Что-то напечатать». Так что я хочу: из второго процесса я просто хочу прочитать эту строку («Что-то напечатать»). , а затем из этого (2-й процесс) Я хочу написать на свой stdin, а затем снова хочу прочитать, как 1-й процесс (дочерний процесс) записывает на stdout. Итак, расскажите, как я могу это сделать? –

+0

Я прокомментировал код. Теперь вы должны делать то, что хотите. Яснее? – User

+0

мой родительский процесс зависает (останавливается навсегда), если я использую p.stdout.read()/readline(), когда дочерний процесс ожидает ввода пользователя. –

Смежные вопросы