Обход буферизации вывода подпроцесса с помощью popen в C или Python

StackOverflow https://stackoverflow.com/questions/1410849

  •  05-07-2019
  •  | 
  •  

Вопрос

У меня есть общий вопрос о popen (и всех связанных функциях), применимый ко всем операционным системам, когда я пишу скрипт на python или некоторый код на c и запускаю полученный исполняемый файл из консоли (win или linux), я могу немедленно увидеть вывод из процесса. Однако, если я запускаю тот же исполняемый файл, что и разветвленный процесс с его stdout, перенаправленным в канал, выходные буферы где-то, обычно до 4096 байт, перед записью в канал, где родительский процесс может его прочитать.

Следующий скрипт на python сгенерирует выходные данные кусками по 1024 байта

import os, sys, time

if __name__ == "__main__":
     dye = '@'*1024
     for i in range (0,8):
        print dye
        time.sleep(1)

Следующий скрипт python выполнит предыдущий скрипт и прочитает вывод, как только он попадет в канал, побайтово / <> p>

import os, sys, subprocess, time, thread

if __name__ == "__main__":
    execArgs = ["c:\\python25\\python.exe", "C:\\Scripts\\PythonScratch\\byte_stream.py"]

    p = subprocess.Popen(execArgs, bufsize=0, stdout=subprocess.PIPE)
    while p.returncode == None:
        data = p.stdout.read(1)
        sys.stdout.write(data)
        p.poll()

Настройте путь для вашей операционной системы. При запуске в этой конфигурации выходные данные будут отображаться не порциями 1024, а порциями 4096, несмотря на то, что для размера буфера команды popen установлено значение 0 (в любом случае это значение по умолчанию). Может кто-нибудь сказать мне, как изменить это поведение ?, есть ли способ заставить операционную систему обрабатывать вывод от разветвленного процесса так же, как при запуске из консоли?, То есть просто передавать данные через без буферизации?

Это было полезно?

Решение

Как правило, стандартная библиотека времени выполнения C (более или менее работающая от имени почти каждой программы в каждой системе ;-) определяет, является ли stdout терминалом или нет; в противном случае он буферизует вывод (что может быть огромным выигрышем в эффективности по сравнению с небуферизованным выводом).

Если вы контролируете программу, которая выполняет написание, вы можете (как предлагает другой ответ) непрерывно очищать стандартный вывод или (более элегантно, если это возможно) пытаться заставить стандартный вывод быть небуферизованным, например, запустив Python с флагом командной строки -u :

-u     : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)
         see man page for details on internal buffering relating to '-u'

(страница справки добавляет упоминание о stdin и проблемах с двоичным режимом [s]).

Если вы не можете или не хотите касаться программы, которая пишет, -u или тому подобное в программе, которая только что читает, вряд ли поможет (буферизация, которая важнее всего, это одно происходит на stdout писателя, а не на stdin читателя). Альтернатива состоит в том, чтобы заставить писателя поверить, что он пишет в терминал (хотя на самом деле он пишет в другую программу!) Через стандартный библиотечный модуль pty или стороннюю стороннюю организацию более высокого уровня pexpect (или, для Windows, его порт wexpect ).

Другие советы

Это правильно и применимо как к Windows, так и к Linux (и, возможно, к другим системам), с popen () и fopen () . Если вы хотите, чтобы выходной буфер отправлялся раньше 4096 байт, используйте fflush () (на C) или sys.stdout.flush () (Python).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top