Принудительно небуферизовать стандартный вывод другой программы с помощью Python - PullRequest
13 голосов
/ 09 октября 2009

Сценарий python управляет внешним приложением в Linux, передает входные данные через канал в stdin внешних приложений и считывает выходные данные через канал из стандартного stdout внешних приложений.

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

Внешнее приложение нельзя изменить для добавления явных вызовов fflush (0).

Как можно использовать модуль pty стандартной библиотеки python вместе с модулем подпроцесс для достижения этой цели?

Ответы [ 7 ]

6 голосов
/ 10 октября 2009

Вы можете использовать PTY для решения этой проблемы:

  • Создание пары pty master / slave;
  • Подключение stdin, stdout и stderr дочернего процесса к ведомому устройству pty;
  • Чтение и запись в pty-мастер в родительском файле.
5 голосов
/ 09 октября 2009

Это возможно, но единственное решение, которое я могу придумать, это довольно запутанный, непереносимый и, вероятно, чреватый проблемными деталями.Вы можете использовать LD_PRELOAD, чтобы внешнее приложение загружало динамическую библиотеку, которая содержит конструктор, который вызывает setvbuf для отмены буфера stdout.Возможно, вы также захотите обернуть setvbuf в библиотеку, чтобы приложение явно не буферизировало свой собственный стандартный вывод.И вы захотите обернуть fwrite и printf так, чтобы они сбрасывались при каждом вызове.Написание .so для предварительной загрузки выведет вас за пределы Python.

3 голосов
/ 09 октября 2009

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

Обратите внимание, что хорошо известная команда, такая как file , имеет параметр (-n), который заставляет ее явно сбрасывать вывод. Это необходимо при использовании файла в режиме, в котором он читает имена входных файлов из канала и печатает обнаруженный тип. Поскольку в этом режиме файловая программа не завершает свою работу, в противном случае выходные данные не отображаются.

Рассмотрим это на более низком уровне: выходная буферизация просто означает, что выполнение write() в буферизованном потоке копирует данные в буфер в памяти до тех пор, пока буфер не заполнится или (как правило), пока не будет найден перевод строки. Затем часть буфера до переполнения или перевода строки записывается write() n в базовый файловый дескриптор системного уровня (который может быть файлом, каналом, сокетом, ...).

Я не понимаю, как вы собираетесь убедить эту программу очистить свой буфер извне.

2 голосов
/ 07 июня 2011

Может помочь ответ на этот вопрос:

Python Запустить подпроцесс демона и прочитать стандартный вывод

Кажется, что он решает ту же проблему.

2 голосов
/ 09 октября 2009

Стоит отметить, что некоторые программы буферизуют свои выходные данные только тогда, когда считают, что они не предназначены для «реального пользователя» (т. Е. Tty). Когда они обнаруживают, что их выходные данные читаются другой программой, они буферизуются.

Эмуляция tty - это одна из вещей, которую ожидает при автоматизации других процессов.

Существует чистая Python-реализация Expect , но я не знаю, насколько хорошо она справляется с эмуляцией tty.

1 голос
/ 28 февраля 2012

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

0 голосов
/ 09 октября 2009

Попробуйте запустить интерпретатор Python с аргументом -u:

python -u myscript.py

Это заставляет Python использовать небуферизованный стандартный ввод / вывод, что может вам помочь.

...