2014-10-16 3 views
2

Я хочу сделать оболочку Python для другой командной строки.Прямое чтение/запись в подпроцесс stdin/stdout

Я хочу как можно быстрее прочитать Python's stdin, фильтровать и перевести его, а затем быстро записать его в программу stdin дочерней программы.

В то же время, я хочу как можно быстрее читать от дочерней программы stdout и после небольшого массирования быстро направить ее на stdout Python.

Модуль подпроцесса Python содержит предупреждения для использования communicate(), чтобы избежать взаимоблокировок. Однако communicate() не дает мне доступ к дочерней программе stdout до тех пор, пока ребенок не завершится.

+0

, пожалуйста, отправьте фрагмент того, как вы пытаетесь, thnx. – user1269942

+0

@ user1269942 Я не знаю, какой API использовать. Чтение через «подпроцесс», ни один из них не подходит. – Will

+1

, связанный с проблемой буферизации: [Подпроцесс программы Python C зависает в «для строки в iter»] (http://stackoverflow.com/q/20503671/4279) – jfs

ответ

1

Я думаю, что все будет хорошо (тщательно), игнорируя предупреждения, используя Popen.stdin и т. Д. Самостоятельно. Просто не забудьте обработать потоки по очереди и перебирать их по справедливому графику, чтобы не заполнять какие-либо буферы. Относительно простой (и неэффективный) способ сделать это в Python - использовать отдельные потоки для трех потоков. Вот как это делается Popen.communicate. Ознакомьтесь с его исходным кодом, чтобы узнать, как это сделать.

+0

Как отмечено @Vorticity ниже, программы, прикрепленные к PIPE, обычно буферизуют их вывод. Чтобы обойти это, я использовал 'pty.openpty' для создания главного подчиненного для stdout ребенка. Вы устанавливаете stdout subprocess.Popen для подчиненного устройства и используете поток для чтения из мастера. – Will

+0

@ Будем О, ладно, это была твоя проблема. Извините, я не понял, но ваше решение звучит неплохо. – 5gon12eder

+0

@Will: Не игнорируйте предупреждение, если вы не понимаете его очень хорошо, иначе программа, которая проходит все тесты, может висеть на производстве (это не сложно понять, просто убедитесь, что вы это делаете). '.communicate()' использует потоки только в Windows, в противном случае используется [цикл выбора] (https://hg.python.org/cpython/file/tip/Lib/subprocess.py#l1603) – jfs

1

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

Сообщите, что у вас есть процесс proc созданный subprocess.Popen. proc имеет атрибуты stdin и stdout. Эти атрибуты являются просто файловыми объектами. Итак, чтобы отправить информацию через stdin, вы должны позвонить по телефону proc.stdin.write(). Чтобы получить информацию от proc.stdout, вы должны позвонить proc.stdout.readline(), чтобы прочитать отдельную строку.

Несколько предостережений:

  • При записи proc.stdin через write() вам нужно будет закончить ввод с символом новой строки. Без символа новой строки ваш подпроцесс будет висеть до тех пор, пока не будет передана новая строка.
  • Чтобы прочитать информацию от proc.stdout, вам необходимо убедиться, что команда, вызываемая подпроцессом, соответствующим образом очищает буфер stdout после каждого оператора печати и каждая строка заканчивается новой строкой. Если буфер stdout не сбрасывается в соответствующие моменты времени, ваш звонок на proc.stdout.readline() будет зависать.
+1

Я обнаружил, что могу обмануть большинство дочерних программ, предоставив им ' pty.openpty() 'stdout. Это позволяет им выполнять буферизацию строк, а не буферизацию большого блока. – Will

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