У меня возникла странная проблема с модулем ведения журнала Python в Windows. Код ниже показывает это:
import multiprocessing
import logging
import sys
class ProcessLogger(multiprocessing.Process):
def __init__(self):
super().__init__()
self.create_logger()
print('state of logger in main proccess:')
print(self.logger)
print(self.logger.handlers)
def run(self):
print('state of logger in child proccess:')
print(self.logger)
print(self.logger.handlers)
def create_logger(self):
self.logger = logging.getLogger('something')
self.logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
self.logger.addHandler(handler)
if __name__ == '__main__':
logg = ProcessLogger()
logg.start()
logg.join()
print(sys.version)
он печатает следующий вывод в Windows:
state of logger in main proccess:
<Logger something (DEBUG)>
[<StreamHandler <stderr> (NOTSET)>]
state of logger in child proccess:
<Logger something (WARNING)>
[]
3.7.2 (tags/v3.7.2:9a3ffc0492, Dec 23 2018, 23:09:28) [MSC v.1916 64 bit (AMD64)]
по какой-то причине объект регистратора в новом процессе имеет состояние по умолчанию.
Я попробовал это на ubuntu, и, похоже, он работает так, как ожидалось:
state of logger in main proccess:
<Logger something (DEBUG)>
[<StreamHandler <stderr> (NOTSET)>]
state of logger in child proccess:
<Logger something (DEBUG)>
[<StreamHandler <stderr> (NOTSET)>]
3.7.1 (default, Oct 22 2018, 11:21:55)
[GCC 8.2.0]
Это ожидаемое поведение в Windows? Кто-нибудь может это объяснить?
Причина, по которой вы наблюдаете вышеуказанное поведение в двух операционных системах, связана с разницей между fork
(Unix) и spawn
(Windows) стратегии запуска процесса.
При использовании стратегии fork
дочерний процесс создается как точный клон родительского процесса. Сначала эти два процесса будут идентичными, и дочерний процесс будет иметь общие свойства (открытые файлы, выбор конфигурации и т. д.) родителя.
Вместо этого со стратегией spawn
запускается новый пустой процесс. Процессу предоставляется модуль Python для загрузки и указатель на первую инструкцию для выполнения в методе run
. Все операции, выполненные родителем заранее, не наследуются.
Бьюсь об заклад, то, что вы видите, это просто тот факт, что в Windows нет системного вызова
fork
, поэтому способ порождения подпроцессов отличается и в основном требует создания совершенно нового процесса и передачи некоторого состояния, сериализованного с использованием протоколаpickle
... не всегда все состояние сохраняется