IOError Ошибка ввода/вывода при печати

Я унаследовал некоторый код, который периодически (случайно) дает сбой из-за ошибки ввода/вывода, возникающей во время вызова печати. Я пытаюсь определить причину возникновения исключения (или, по крайней мере, лучше понять его) и как правильно с ним справиться.

При выполнении следующей строки Python (в интерпретаторе 2.6.6, работающем на CentOS 5.5):

print >> sys.stderr, 'Unable to do something: %s' % command

Возникает исключение (трассировка опущена):

IOError: [Errno 5] Input/output error

Для контекста это обычно то, что большая функция пытается сделать в то время:

from subprocess import Popen, PIPE
import sys
def run_commands(commands):
    for command in commands:
        try:
            out, err = Popen(command, shell=True, stdout=PIPE, stderr=PIPE).communicate()
            print >> sys.stdout, out
            if err:
                raise Exception('ERROR -- an error occurred when executing this command: %s --- err: %s' % (command, err))
        except:
            print >> sys.stderr, 'Unable to do something: %s' % command
run_commands(["ls", "echo foo"])

Синтаксис >> мне не особенно знаком, я редко его использую, и я понимаю, что это, возможно, наименее предпочтительный способ записи в stderr. Однако я не верю, что альтернативы решат основную проблему.

Из документации, которую я прочитал, IOError 5 часто неправильно используется и определяется несколько свободно, поскольку разные операционные системы используют его для решения разных проблем. Лучшее, что я вижу в моем случае, это то, что процесс python больше не привязан к терминалу/pty.

Насколько я могу судить, ничто не отключает процесс от потоков stdout/stderr - например, терминал все еще открыт, и все «кажется» в порядке. Может ли это быть вызвано нечистым завершением дочернего процесса? Что еще может быть причиной этой проблемы или какие еще шаги я могу предпринять для ее дальнейшей отладки?

Что касается обработки исключения, я, очевидно, могу его поймать, но я предполагаю, что это означает, что я не смогу печатать на stdout/stderr до конца выполнения? Могу ли я как-то повторно подключиться к этим потокам - возможно, сбросив sys.stdout на sys.__stdout__ и т. д.? В этом случае невозможность записи в stdout/stderr не считается фатальной, но если это указывает на то, что что-то начинает идти не так, я бы предпочел пораньше.

Я предполагаю, что в конечном итоге я немного не понимаю, с чего начать отладку этого...


person Mark Streatfield    schedule 02.05.2012    source источник
comment
Я вижу, что только несколько человек просмотрели этот вопрос без комментариев/ответов. Если вопрос плохо структурирован/неясен, помогите мне улучшить его, чтобы я мог работать над ответом.   -  person Mark Streatfield    schedule 05.05.2012
comment
Я тоже испытываю эту ошибку. Так раздражает, чтобы получить эту ошибку иногда.   -  person Saša Šijak    schedule 13.06.2012
comment
Не расстраивайтесь из-за нескольких ответов; ваш вопрос и формат великолепны; это просто сложный вопрос, чтобы ответить.   -  person culix    schedule 25.12.2013
comment
Итак, удачи? У меня такая же ошибка с модулем multiprocessing и травлением моих данных.   -  person Charlie    schedule 19.09.2014
comment
@Чарли - нет, к сожалению, нет. Ни один из ответов здесь не подходит и не объясняет мой вариант использования. Это то, с чем я научился жить/обходить.   -  person Mark Streatfield    schedule 28.09.2014


Ответы (7)


Я думаю, что это связано с терминалом, к которому подключен процесс. Я получил эту ошибку, когда запустил процесс python в фоновом режиме и закрыл терминал, в котором я его запустил:

$ myprogram.py
Ctrl-Z
$ bg
$ exit

Проблема заключалась в том, что я запустил недемонизированный процесс на удаленном сервере и вышел из системы (закрыв сеанс терминала). Решение состояло в том, чтобы запустить сеанс screen/tmux на удаленном сервере и запустить процесс в этом сеансе. Затем отсоединение сеанса + выход из системы сохраняет терминал, связанный с процессом. Это работает, по крайней мере, в мире * nix.

person jmkg    schedule 08.01.2014
comment
У меня была та же проблема - скрипт на удаленном сервере, который печатает на стандартный вывод. Работает нормально, когда я подключен через ssh, но когда я выхожу из системы до того, как он напечатает, код вызывает ошибку IOError. Этот аналогичный вопрос имеет тоже очень хороший ответ. - person Jeyekomon; 22.05.2018

У меня была очень похожая проблема. У меня была программа, которая запускала несколько других программ, используя модуль подпроцесса. Затем эти подпроцессы будут выводить вывод на терминал. Я обнаружил, что когда я закрывал основную программу, она не завершала автоматически подпроцессы (как я предполагал), а продолжали работать. Таким образом, если я завершал работу как основной программы, так и терминала, с которого она была запущена*, у подпроцессов больше не было терминала, подключенного к их стандартному выводу, и они выдавали ошибку IOError. Надеюсь, это поможет вам.

*NB: это должно быть сделано в этом порядке. Если вы просто убьете терминал (по какой-то причине), это убьет как основную программу, так и подпроцессы.

person gtg944q    schedule 27.07.2012
comment
То, что вы описываете, имеет смысл для моей ситуации, однако остается вопрос. В соответствии с документами, вызов коммуникация() должен читаться до тех пор, пока не будет достигнут конец файла, и ждать завершения подпроцесса. Поскольку я получаю эту ошибку во время нормального выполнения (я оставляю как родительский, так и дочерний процессы для естественного завершения), означает ли это, что сообщение() возвращается раньше? - person Mark Streatfield; 31.07.2012

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

person zss    schedule 22.12.2012
comment
Нет, к сожалению нет. Много свободного места на диске, по-видимому, не достигает максимального предела дескриптора файла, низкая загрузка процессора и отсутствие подкачки. - person Mark Streatfield; 07.03.2013

Я здесь новичок, поэтому, пожалуйста, простите, если я немного ошибусь, когда дело доходит до деталей кода. Недавно мне удалось выяснить, что вызывает ошибку ввода-вывода оператора печати, когда терминал, связанный с запуском скрипта Python, закрыт. Это связано с тем, что строка, которая должна быть напечатана в stdout/stderr, слишком длинная. В этом случае виновником является строка "out". Чтобы решить эту проблему (без необходимости держать терминал открытым во время выполнения скрипта Python), просто прочитайте строку «out» построчно и напечатайте строку за строкой, пока мы не достигнем конца строки «out». Что-то типа:

while true:
        ln=out.readline()
        if not ln: break
        print ln.strip("\n") # print without new line

Та же проблема возникает, если вы выводите на экран весь список строк. Просто распечатайте список по одному элементу. Надеюсь, это поможет!

person Thang    schedule 10.02.2017
comment
Я могу это проверить. Сброс большей полезной нагрузки на отсоединенный терминал вызывает ошибку. Я предполагаю, что размер полезной нагрузки сокета является проблемой здесь при стандартной загрузке данных на терминал. - person eAlie; 14.01.2019

Это могло произойти, когда ваша оболочка дала сбой, когда печать пыталась записать в нее данные.

person mtmt    schedule 14.04.2016

В моем случае я просто перезапускаю службу, после чего эта проблема исчезает. не теперь, почему. Моя проблема была той же ошибкой ввода/вывода OSError для Odoo.

После перезапуска службы он исчез.

person Robin LI    schedule 01.04.2020

Проблема в том, что вы закрыли канал stdout, в который python пытается записать, когда вызывается print()

Это может быть вызвано запуском скрипта в фоновом режиме с помощью & и последующим закрытием сеанса терминала (т.е. закрытием stdout)

$ python myscript.py &
$ exit

Одним из решений является установка stdout в файл при работе в фоновом режиме.

Пример

$ python myscript.py > /var/log/myscript.log 2>&1 &
$ exit

Нет ошибок на print()

person Bobs Burgers    schedule 13.01.2021