Неблокирование на stdin, с блокировкой на stdout не работает

У меня есть простой скрипт на Python, который умирает после случайного количества вывода.

ИМХО - должно функционировать

Это специфично для Linux, такая же проблема для python2 или python3; не уверен насчет python-mac - у меня нет под рукой mac; И это не проблема Python-Windows.

Проблема, которую я считаю, заключается в интерпретации в Linux блокировок или неблокировок stdio. На мой взгляд, и в большой степени я считаю, что Pythons view STDIN и STDOUT - это два разных файла.

Этот пост рассказывает о проблеме с точки зрения кода на C: когда неблокирующий ввод-вывод включен для stdout, правильно ли для ОС включать его и для stdin?

Проблема: в STDIN установите параметр os.O_NONBLOCK для STDIN.

Ожидаемый результат:

O_NONBLOCK должен применяться только к файлу, к которому он применяется.

Фактический результат:

O_NONBLOCK установлен на STDIN и STDOUT

В результате: Когда ваше приложение пишет в стандартный вывод (или stderr) стандартным способом (например, выводит данные журнала или отладки) в какой-то момент, python2 или python3 завершают работу с ошибкой ввода-вывода в случайное время спустя.

Код ниже демонстрирует проблему

import sys
import fcntl
import os

def show_flags(why):
    print("%s: FLAGS: 0x%08x" % (why,fcntl.fcntl( sys.stdout.fileno(), fcntl.F_GETFL )))

show_flags("startup")
f = fcntl.fcntl( sys.stdin.fileno(), fcntl.F_GETFL )
show_flags("got-stdin")
f = f | os.O_NONBLOCK
fcntl.fcntl( sys.stdin.fileno(), fcntl.F_SETFL, f )
show_flags("set-stdin")

# produce spewing output to show the error.
for x in range(0,10000):
    sys.stdout.write("x=%10d -------- lots of text here to fill buffer\n" % x)

Если я запускаю: "strace -o log python test.py" - и записываю вывод журнала Приведенная часть, показывающая ошибку:

(Начните)

fcntl(1, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
write(1, "startup: FLAGS: 0x00008002\n", 27) = 27
fcntl(0, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
fcntl(1, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
write(1, "got-stdin: FLAGS: 0x00008002\n", 29) = 29
fcntl(0, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0
fcntl(1, F_GETFL)                       = 0x8802 (flags O_RDWR|O_NONBLOCK|O_LARGEFILE)
write(1, "set-stdin: FLAGS: 0x00008802\n", 29) = 29
write(1, "x=         0 -------- lots of te"..., 55) = 55
write(1, "x=         1 -------- lots of te"..., 55) = 55

После некоторого случайного числа записей (от 300 до 500) linux возвращается с ошибкой

write(1, "x=       495 -------- lots of te"..., 55) = 55
write(1, "x=       496 -------- lots of te"..., 55) = -1 EAGAIN (Resource temporarily unavailable)
write(2, "Traceback (most recent call last"..., 35) = -1 EAGAIN (Resource temporarily unavailable)

Предложения?

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

Проблема: приложение хочет / нуждается в мониторинге / чтении STDIN неблокирующим способом, чтобы оно могло обрабатывать выходные данные родителя и действовать в соответствии с ним. Запись журнала не должна приводить к смерти приложения в случайных местах.

Обертывание каждого оператора журнала блоками try/catch - безумие.

Просить богов Linux изменить это поведение не произойдет.

Python3 - по-видимому, повторяет по крайней мере один раз, что иногда успешно, но в большинстве случаев это не так - Python2 вообще не повторяется.

Исправление этого питона INSIDE через пользовательский взлом - это тоже безумие... Я не могу легко распространять свою пользовательскую версию Python.EXE среди всех, кому нужно запустить мое приложение.

Предложения?

0 ответов

Другие вопросы по тегам