У меня довольно большой проект Python, который в настоящее время работает на Linux, но я пытаюсь перейти на Windows. Я сократил код до полного примера, который можно запустить, чтобы проиллюстрировать мои проблемы: у меня есть два класса: «Родительский и детский». Родитель инициализируется первым, создает регистратор, и порождает ребенка, чтобы сделать работу:Python Logging with Multiprocessing in Windows
import logging
import logging.config
import multiprocessing
class Parent(object):
def __init__(self, logconfig):
logging.config.dictConfig(logconfig)
self.logger = logging.getLogger(__name__)
def spawnChild(self):
self.logger.info('One')
c = Child(self.logger)
c.start()
class Child(multiprocessing.Process):
def __init__(self, logger):
multiprocessing.Process.__init__(self)
self.logger = logger
def run(self):
self.logger.info('Two')
if __name__ == '__main__':
p = Parent({
'version':1,
"handlers": {
"console": {
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout"
},
},
"root": {
"level": "DEBUG",
"handlers": [
"console",
]
}
}
)
p.spawnChild()
В Linux (в частности, убунту 12,04), я получаю следующее (ожидаемый) результат:
[email protected]:~$ python test.py
One
Two
Но на Windows (в частности, Windows 7), он терпит неудачу с ошибкой травильной:
C:\>python test.py
<snip>
pickle.PicklingError: Can't pickle <type 'thread.lock'>: it's not found as thread.lock
проблема сводится к тому, отсутствию Windows' истинной вилки, так предметы должны быть маринованными при отправке между потоками. Но регистратор не может быть маринован. Я попытался с помощью __getstate__ и __setstate__, чтобы избежать травления и ссылок по имени в ребенке:
def __getstate__(self):
d = self.__dict__.copy()
if 'logger' in d.keys():
d['logger'] = d['logger'].name
return d
def __setstate__(self, d):
if 'logger' in d.keys():
d['logger'] = logging.getLogger(d['logger'])
self.__dict__.update(d)
Это работает в Linux так же, как и раньше, и теперь Windows, не проваливается с PicklingError. Тем не менее, мой выход только из Родитель:
C:\>python test.py
One
C:\>
кажется, что ребенок не может использовать регистратор, несмотря на отсутствие сообщения с жалобами «Нет регистратор не может быть найден для обработчика„__main__“» или любое другое сообщение об ошибке. Я огляделся, и есть средства, с помощью которых я мог бы полностью реструктурировать, как я вхожу в мою программу, но это, безусловно, последнее средство. Я надеюсь, что я просто упустил что-то очевидное и что мудрость толпы может указать на меня.
'if key in some_dict.keys()' - это точно * неправильный способ выполнения этой проверки. Это займет время O (n) в python2. Просто используйте 'if key in some_dict'. Что касается вашей проблемы. Подпроцесс может иметь различный stdout и, следовательно, вы не видите вывод. Попробуйте добавить обработчик файла и проверить правильность вывода в файле. – Bakuriu
Оцените примечание о ключе, которое было просто скопировано из другого сообщения SO для тестирования. Все мои фактические протоколирования выполняются в файлах, и проблема все еще возникает. Для создания вышеуказанного скрипта stdout было просто проще протестировать. Использование "multi_file_handler": { "класс": "logging.handlers.RotatingFileHandler", "имя файла": "output.log" }, приводит к той же проблеме - "One \ Ntwo" на Linux, «One "на окнах – user2093082
Проблема может заключаться в том, что при распаковке' __init__' обычно вызывается * not *. Это означает, что подпроцесс * не * вызывает 'logging.config.dictConfig (...) 'и, следовательно, он может использовать конфигурацию по умолчанию. Попытайтесь изменить метод '__setstate__', чтобы он вызывал' dictConfig' с правильными настройками и видел, что-то меняется. – Bakuriu