Неблокирование на 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 среди всех, кому нужно запустить мое приложение.
Предложения?