Питон:Почему `sys.exit(msg)`, вызываемый из потока, не выводит `msg` в stderr?
-
05-07-2019 - |
Вопрос
Сегодня я столкнулся с тем фактом, что sys.exit()
вызываемый из дочернего потока, не останавливает основной процесс.Я не знал этого раньше, и это нормально, но мне потребовалось много времени, чтобы осознать это.Это спасло бы много-много времени, если sys.exit(msg)
напечатал бы msg
Для stderr
.Но этого не произошло.
Оказалось, что это не была настоящая ошибка в моем приложении;это называлось sys.exit(msg)
со значимой ошибкой волевым способом - но я просто не мог этого увидеть.
В документах для sys.exit()
это заявлено:
"[...] любой другой объект печатается для sys.stderr
и приводит к получению кода выхода, равного 1"
Это неправда для вызова из дочернего потока, где sys.exit()
очевидно, ведет себя как thread.exit()
:
"Вызовите исключение SystemExit.Если это не будет перехвачено, это приведет к завершению потока молча"
Я думаю, когда программист хочет sys.exit(msg)
чтобы напечатать сообщение об ошибке, это должно быть просто напечатано - независимо от места, откуда оно вызывается.Почему бы и нет?В настоящее время я не вижу никакой причины.По крайней мере, в документах должна быть подсказка для sys.exit()
что сообщение не печатается из потоков.
А ты как думаешь?Почему сообщения об ошибках скрыты от потоков?Есть ли в этом смысл?
С наилучшими пожеланиями,
Jan-Philip Gehrcke
Решение
Я согласен, что документы Python неверны или, может быть, точнее, неполны в отношении sys.exit и SystemExit при вызове / вызове потоками, отличными от основного;пожалуйста, откройте проблему с документом на онлайн-трекере Python, чтобы это можно было решить в будущей итерации документов (вероятно, в ближайшем будущем - исправления в документе проще и плавнее, чем исправления в коде;-).
Конечно, решение довольно простое - просто оберните любую функцию, которую вы используете в качестве целевого объекта threading.Thread
с декоратором, который выполняет try
/except SystemExit, e:
вокруг этого и выполняет "запись в stderr" дополнительную функциональность, которая вам требуется (или, может быть, лучше, использует вместо этого вызов logging.error) перед завершением работы.Но, учитывая проблему с документом, на которую вы правильно указали, трудно думать об этом до тех пор, пока кто-то не столкнется с проблемой и фактически не потратит некоторое время на отладку, чтобы определить ее, как вам пришлось сделать (от коллективного имени основных разработчиков python - извините!).
Другие советы
Не все потоки в python равны.Вызов sys.exit из потока фактически не приводит к выходу из системы.Таким образом, вызов sys.exit() из дочернего потока бессмыслен, поэтому имеет смысл, что он ведет себя не так, как вы ожидаете.
Это Страница больше рассказывает о потоковых объектах и различиях между потоками и специальным "основным" потоком.