подпроцесс. Popen.stdout - читающий stdout в режиме реального времени (снова)

Снова, тот же вопрос.
Причина - я все еще не могу заставить ее работать после чтения следующего:

Мой случай - то, что мне записали консольное приложение в C, позволяет, берут, например, этот код в цикле:

tmp = 0.0;   
printf("\ninput>>"); 
scanf_s("%f",&tmp); 
printf ("\ninput was: %f",tmp); 

Это непрерывно читает некоторый вход и пишет некоторый вывод.

Мой код Python для взаимодействия с ним следующий:

p=subprocess.Popen([path],stdout=subprocess.PIPE,stdin=subprocess.PIPE)
p.stdin.write('12345\n')
for line in p.stdout: 
    print(">>> " + str(line.rstrip())) 
    p.stdout.flush() 

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

Я попробовал Python 2.6 и 3.1, но версия не имеет значения - я просто должен заставить его работать где-нибудь.

12
задан Community 23 May 2017 в 11:46
поделиться

2 ответа

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

Для более скромных объемов данных может быть достаточно метода Popen.communicate(). Однако, для данных, превышающих его буферизацию, вы, вероятно, получите остановленные процессы (подобно тому, что вы уже наблюдаете?)

Возможно, вам стоит поискать подробности об использовании модуля fcntl и сделать один или другой (или оба) ваших файловых дескрипторов неблокирующими. В этом случае, конечно, вам придется обернуть все чтения и/или записи в эти файловые дескрипторы в соответствующую обработку исключений для обработки событий "EWOULDBLOCK". (Я не помню точное исключение Python, которое возникает при таких событиях).

Совершенно другим подходом было бы использование родительским процессом модуля select и os.fork() ... а дочерним процессом - execve() целевой программы после непосредственной обработки любого файла dup()ing. (По сути, вы повторно реализуете часть Popen(), но с другой обработкой дескриптора родительского файла (PIPE).

Кстати, .communicate, по крайней мере в стандартных библиотеках Python 2.5 и 2.6, обрабатывает только около 64K удаленных данных (в Linux и FreeBSD). Это число может меняться в зависимости от различных факторов (возможно, включая параметры сборки, используемые для компиляции вашего интерпретатора Python, или версию libc, подключаемую к нему). Оно НЕ просто ограничено доступной памятью (несмотря на утверждение J.F. Sebastian об обратном), но ограничено гораздо меньшим значением.

3
ответ дан 2 December 2019 в 23:42
поделиться

Передать чтение из конвейера в отдельный поток, который сигнализирует, когда доступен фрагмент вывода:

Как я могу прочитать все доступные данные из subprocess.Popen.stdout (без блокировки)?

1
ответ дан 2 December 2019 в 23:42
поделиться
Другие вопросы по тегам:

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