Прямо сейчас у меня есть центральный модуль в платформе, которая порождает несколько процессов, используя multiprocessing
модуль Python 2.6 . Поскольку он использует multiprocessing
, существует журнал, поддерживающий многопроцессорность на уровне модуля LOG = multiprocessing.get_logger()
. Согласно документам , этот регистратор имеет общие блокировки процессов, так что вы не можете вписаться sys.stderr
(или в какой-либо другой дескриптор файла), имея несколько процессов, пишущих в него одновременно.
У меня сейчас проблема в том, что другие модули в фреймворке не поддерживают многопроцессорность. Как мне кажется, мне нужно сделать так, чтобы все зависимости этого центрального модуля использовали многопроцессорное ведение журнала. Это раздражает в рамках, не говоря уже о всех клиентах платформы. Есть ли альтернативы, о которых я не думаю?
источник
multiprocessing.get_logger()
? Похоже, что на основе этих других способов ведения журнала функциональность регистрации неmultiprocessing
имеет большого значения.get_logger()
это регистратор, используемый самимmultiprocessing
модулем. Это полезно, если вы хотите отладитьmultiprocessing
проблему.Ответы:
Единственный способ справиться с этим ненавязчиво - это:
select
из файловых дескрипторов каналов выполняйте сортировку слиянием доступных записей журнала и переходите к централизованному журналу. Повторите.)источник
atexit
:-). Проблема в том, что он не даст вам показания в реальном времени. Это может быть частью цены многопроцессорной обработки, а не многопоточности.multiprocessing.Queue
не будет проще, если нужно переписать много кодаmultiprocessing.Queue
и / или если проблема в производительностиЯ только что написал собственный обработчик журнала, который просто передает все в родительский процесс через канал. Я тестировал его всего десять минут, но, похоже, он работает довольно хорошо.
( Примечание: это жестко запрограммировано
RotatingFileHandler
, это мой собственный вариант использования.)Обновление: @javier теперь поддерживает этот подход как пакет, доступный в Pypi - см. Multiprocessing -logging on Pypi, github по адресу https://github.com/jruere/multiprocessing-logging
Обновление: реализация!
Теперь он использует очередь для правильной обработки параллелизма, а также корректно восстанавливается после ошибок. Я уже использую это в производстве в течение нескольких месяцев, и текущая версия ниже работает без проблем.
источник
multiprocessing.Queue
использует поток, чтобы вput()
. Поэтому не вызывайтеput
(т. Е. Регистрируйте сообщения с помощьюMultiProcessingLog
обработчика) перед созданием всех подпроцессов. В противном случае поток будет мертв в дочернем процессе. Одним из решений является вызовQueue._after_fork()
в начале каждого дочернего процесса или использованиеmultiprocessing.queues.SimpleQueue
вместо него, которое не связано с потоком, но блокирует.multiprocessing-logging
.QueueHandler
является родным в Python 3.2+, и делает именно это. Это легко копируется в предыдущих версиях.Документы Python содержат два полных примера: ведение журнала в один файл из нескольких процессов
Для тех, кто использует Python <3.2, просто скопируйте
QueueHandler
в свой собственный код с: https://gist.github.com/vsajip/591589 или альтернативно импортируйте logutils .Каждый процесс (включая родительский процесс) помещает свою
Queue
запись в журнал , а затемlistener
поток или процесс (для каждого из них предоставляется один пример) выбирает их и записывает их все в файл - без риска повреждения или искажения.источник
Ниже приведено еще одно решение с упором на простоту для всех, кто (как и я), попал сюда из Google. Регистрация должна быть легкой! Только для 3.2 или выше.
источник
QueueHandler
ИQueueListener
классы могут быть использованы на Python 2.7 , а также, доступны вlogutils
пакете.Еще одной альтернативой могут быть различные не-файловые обработчики журналирования в
logging
пакете :SocketHandler
DatagramHandler
SyslogHandler
(и другие)
Таким образом, вы могли бы легко иметь демон ведения журнала, в который вы могли бы писать безопасно и обрабатывать результаты правильно. (Например, простой сервер сокетов, который просто распаковывает сообщение и отправляет его в свой собственный обработчик вращающихся файлов.)
Это
SyslogHandler
позаботится и о тебе. Конечно, вы можете использовать свой собственный экземплярsyslog
, а не системный.источник
Вариант других, в котором ведение журнала и потока очереди разделены.
источник
fileConfig()
в MainProcess и едва настроенный регистратор в PoolWorkers (только сsetLevel(logging.NOTSET)
). Как я уже упоминал в другом комментарии, я использую пул, поэтому мне пришлось получать мою очередь (прокси-сервер) из диспетчера вместо многопроцессорной обработки, чтобы ее можно было засолить. Это позволяет мне передавать очередь работнику внутри словаря (большая часть которого получена из объекта argsparsevars()
). Я чувствую, что, в конце концов, это лучший подход для MS Windows, в котором отсутствует функция fork () и не используется решение @zzzeak.fork
. Таким образом, каждый процесс будет иметь свою собственную независимую бесполезную очередь. Второй подход в связанном Q / A не будет работать на таких платформах. Это способ непереносимого кода.multiprocessing.Queue
основной процесс, и с тех пор использую его постоянно. Не претендую на понимание, почему это работает.Все текущие решения слишком связаны с конфигурацией регистрации с помощью обработчика. Мое решение имеет следующую архитектуру и функции:
multiprocessing.Queue
logging.Logger
(и уже определенных экземплярах) вносятся исправления для отправки всех записей в очередьКод с примером использования и выходом можно найти по следующему адресу : https://gist.github.com/schlamar/7003737
источник
daemon_thread.daemon
наTrue
. Мне нужно было сделать это, чтобы заставить мою программу на Python правильно завершиться, когда в диспетчере контекста происходит исключение.func
вlogged_call
противном случае исключение искажалось бы с другими зарегистрированными выходными данными. Вот моя модифицированная версия этого: gist.github.com/blah238/8ab79c4fe9cdb254f5c37abfc5dc85bfТак как мы можем представлять многопроцессорное ведение журнала как много издателей и одного подписчика (слушателя), используя ZeroMQ для реализации обмена сообщениями PUB-SUB действительно является опцией.
Кроме того, модуль PyZMQ , привязки Python для ZMQ, реализует PUBHandler , который является объектом для публикации сообщений регистрации через сокет zmq.PUB.
В Интернете есть решение для централизованного ведения журналов из распределенного приложения с использованием PyZMQ и PUBHandler, которое может быть легко адаптировано для локальной работы с несколькими процессами публикации.
источник
Мне также нравится ответ zzzeek, но Андре прав, что для предотвращения искажений требуется очередь. Мне немного повезло с трубкой, но я увидел искаженный звук, что несколько ожидаемо. Реализовать его оказалось сложнее, чем я думал, в частности из-за работы в Windows, где есть некоторые дополнительные ограничения в отношении глобальных переменных и прочего (см .: Как реализована многопроцессорная обработка Python в Windows? )
Но, наконец, я получил это работает. Этот пример, вероятно, не идеален, поэтому комментарии и предложения приветствуются. Он также не поддерживает настройку форматера или чего-либо другого, кроме корневого регистратора. По сути, вам нужно переустановить регистратор в каждом из процессов пула с очередью и настроить другие атрибуты в регистраторе.
Опять же, любые предложения о том, как сделать код лучше, приветствуются. Я, конечно, еще не знаю всех трюков Python :-)
источник
if 'MainProcess' == multiprocessing.current_process().name:
можно ли использовать вместо проходаchild
?просто опубликуйте где-нибудь свой экземпляр регистратора. таким образом, другие модули и клиенты могут использовать ваш API, чтобы получить регистратор без необходимости
import multiprocessing
.источник
import logging; logging.basicConfig(level=logging.DEBUG); logging.debug('spam!')
из любого места и заставить его работать должным образом.Мне понравился ответ zzzeek. Я бы просто заменил канал на очередь, поскольку, если несколько потоков / процессов используют один и тот же конец канала для создания сообщений журнала, они будут искажены.
источник
Как насчет делегирования всего ведения журнала другому процессу, который считывает все записи журнала из очереди?
Просто поделитесь LOG_QUEUE с помощью любого из многопроцессорных механизмов или даже наследования, и все это прекрасно работает!
источник
У меня есть решение, похожее на Ironhacker, за исключением того, что я использую logging.exception в своем коде и обнаружил, что мне нужно отформатировать исключение, прежде чем передать его обратно через очередь, так как трассировки не могут быть задействованы:
источник
Ниже приведен класс, который можно использовать в среде Windows, требуется ActivePython. Вы также можете наследовать для других обработчиков журналов (StreamHandler и т. Д.)
И вот пример, который демонстрирует использование:
источник
multiprocessing.Lock()
вместо Windows Mutex сделает решение переносимым.Вот мой простой взлом / обходной путь ... не самый полный, но легко модифицируемый и более простой для чтения и понимания, я думаю, чем любые другие ответы, которые я нашел до написания этого:
источник
Есть этот отличный пакет
Пакет: https://pypi.python.org/pypi/multiprocessing-logging/
код: https://github.com/jruere/multiprocessing-logging
Установка:
Затем добавьте:
источник
Одна из альтернатив - записать протокол многопроцессорной обработки в известный файл и зарегистрировать
atexit
обработчик для присоединения к этим процессам, считав его обратно на stderr; тем не менее, вы не получите поток в реальном времени к выводимым сообщениям на stderr таким образом.источник
Если у вас есть взаимоблокировки, возникающие в комбинации блокировок, потоков и вилок в
logging
модуле, это сообщается в отчете об ошибке 6721 (см. Также связанный вопрос SO ).Существует небольшая Fixup решение размещена здесь .
Тем не менее, это просто исправит любые потенциальные тупики в
logging
. Это не исправит, что вещи могут быть искажены. Смотрите другие ответы, представленные здесь.источник
Простейшая идея как упомянуто:
[WatchedFileHandler][1]
. Причины этого обработчика подробно обсуждаются здесь , но вкратце существуют некоторые худшие условия гонки с другими обработчиками журналирования. У этого есть самое короткое окно для условия гонки.источник
Для тех, кому это может понадобиться, я написал декоратор для пакета multiprocessing_logging, который добавляет текущее имя процесса в журналы, так что становится понятно, кто что регистрирует.
Он также запускает install_mp_handler (), поэтому запускать его перед созданием пула становится бесполезно.
Это позволяет мне видеть, какой работник создает какие журналы сообщений.
Вот план с примером:
источник
Моим детям, которые десятилетиями сталкивались с той же проблемой и нашли этот вопрос на этом сайте, я оставляю этот ответ.
Простота против усложнения. Просто используйте другие инструменты. Python потрясающий, но он не был предназначен для некоторых вещей.
Следующий фрагмент демона logrotate работает для меня и не слишком усложняет ситуацию. Запланируйте это, чтобы работать ежечасно и
Вот как я его устанавливаю (символические ссылки не работают для logrotate):
источник