Вопрос по python – Чтение / запись в подпроцесс Popen ()

9

Я пытаюсь поговорить с дочерним процессом с помощью вызова python subprocess.Popen (). В моем реальном коде я реализую тип IPC, поэтому я хочу написать некоторые данные, прочитать ответ, написать еще несколько данных, прочитать ответ и так далее. Из-за этого я не могу использовать Popen.communicate (), который в других случаях хорошо работает для простого случая.

Этот код показывает мою проблему. Он даже не получает первый ответ, зависает при первом «чтении результата». Зачем? Как я могу сделать эту работу, как я ожидаю?

<code>import subprocess
p = subprocess.Popen(["sed", 's/a/x/g'],
                     stdout = subprocess.PIPE,
                     stdin = subprocess.PIPE)

p.stdin.write("abc\n")
print "Reading result:"
print p.stdout.readline()

p.stdin.write("cat\n")
print "Reading result:"
print p.stdout.readline()
</code>

Ваш Ответ

2   ответа
4

sedВыходные данные буферизуются и выводят свои данные только до тех пор, пока не будет накоплено достаточное количество или входной поток не будет исчерпан и закрыт.

Попробуй это:

import subprocess
p = subprocess.Popen(["sed", 's/a/x/g'],
                     stdout = subprocess.PIPE,
                     stdin = subprocess.PIPE)

p.stdin.write("abc\n")
p.stdin.write("cat\n")
p.stdin.close()

print "Reading result 1:"
print p.stdout.readline()

print "Reading result 2:"
print p.stdout.readline()

Имейте в виду, что это не может быть сделано надежно, что огромные данные какstdin блокирует, когда буфер заполнен. Лучший способ сделать это с помощьюcommunicate().

Но sed не действует таким образом, когда запускает команду в оболочке напрямую. Если вы это сделаете, ответ приходит после каждой строки. И проблема остается, даже если я вызываю p.stdin.flush () после записи. Кроме того, в реальной жизни я также написал вызываемую программу, буферизация отсутствует, и она ведет себя так же. Я не уверен, что проблема заключается в буферизации. Mats Ekberg
Ах, вы были правы, буферизация была действительно проблемой. Mats Ekberg
4

Я бы попробовал использоватьPopen().communicate() если вы можете, как это делает много хорошего для вас, но если вам нужно использоватьPopen() Точно так же, как вы описали, вам нужно установить sed для очистки буфера после новых строк с помощью-l опция:

p = subprocess.Popen(['sed', '-l', 's/a/x/g'],
                     stdout=subprocess.PIPE,
                     stdin=subprocess.PIPE)

и ваш код должен работать нормально

Да, проблема решена. Проблема была в буферизации вывода результата. Выполнение простого stdout.flush () в моем подпроцессе решило проблему. Спасибо! Mats Ekberg
Действительно, это работает! Мой sed по какой-то причине использует -u для «unbuffered», а не -l, но все равно работает. Это решает мой пример кода, но, к сожалению, не мой настоящий код, поскольку фактическая команда не sed, а другая программа на python. Хороший ответ, хотя, вы определили проблему. Mats Ekberg

Похожие вопросы