gpt4 book ai didi

在 Windows 中使用多处理进行 Python 日志记录

转载 作者:可可西里 更新时间:2023-11-01 09:28:49 26 4
gpt4 key购买 nike

我有一个相当大的 Python 项目,目前在 Linux 上运行,但我正在尝试扩展到 Windows。我已经将代码缩减为一个完整的示例,可以运行它来说明我的问题:我有两个类,Parent 和 Child。 Parent 首先被初始化,创建一个记录器,然后生成一个 Child 来做工作:

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(特别是 ubuntu 12.04)上,我得到以下(预期)输出:

user@ubuntu:~$ python test.py 
One
Two

但是,在 Windows 上(特别是 Windows 7),它会因 pickling 错误而失败:

C:\>python test.py
<snip>
pickle.PicklingError: Can't pickle <type 'thread.lock'>: it's not found as thread.lock

问题归结为 Windows 缺少真正的 fork,因此在线程之间发送对象时必须对其进行 pickle。但是,记录器不能被腌制。我尝试使用 __getstate__ 和 __setstate__ 来避免酸洗,并在 Child 中按名称引用:

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__'的记录器”或任何其他错误消息,但 child 似乎无法使用记录器。我环顾四周,发现有一些方法可以完全重组我的程序登录方式,但这显然是最后的手段。我希望我只是遗漏了一些明显的东西,并且人群的智慧可以向我指出。

最佳答案

在大多数情况下,Logger 对象是不可挑选的,因为它们在内部使用不可挑选的 theading.Lock 和/或 file 对象。您尝试的解决方法确实避免了 pickling logger,但它最终在子进程中创建了一个完全不同的 Logger,它恰好与 Logger 同名 在父级;您进行的 logging.config 调用的效果将丢失。要获得您想要的行为,您需要在子进程中重新创建记录器重新调用logging.config.dictConfig:

class Parent( object ):
def __init__(self, logconfig):
self.logconfig = logconfig
logging.config.dictConfig(logconfig)
self.logger = logging.getLogger(__name__)

def spawnChild(self):
self.logger.info('One')
c = Child(self.logconfig)
c.start()

class Child(multiprocessing.Process):
def __init__(self, logconfig):
multiprocessing.Process.__init__(self)
self.logconfig = logconfig

def run(self):
# Recreate the logger in the child
logging.config.dictConfig(self.logconfig)
self.logger = logging.getLogger(__name__)

self.logger.info('Two')

或者,如果您想继续使用 __getstate__/__setstate__:

class Parent( object ):
def __init__(self, logconfig):
logging.config.dictConfig(logconfig)
self.logger = logging.getLogger(__name__)
self.logconfig = logconfig

def spawnChild(self):
self.logger.info('One')
c = Child(self.logger, self.logconfig)
c.start()

class Child(multiprocessing.Process):
def __init__(self, logger, logconfig):
multiprocessing.Process.__init__(self)
self.logger = logger
self.logconfig = logconfig

def run(self):
self.logger.info('Two')

def __getstate__(self):
d = self.__dict__.copy()
if 'logger' in d:
d['logger'] = d['logger'].name
return d

def __setstate__(self, d):
if 'logger' in d:
logging.config.dictConfig(d['logconfig'])
d['logger'] = logging.getLogger(d['logger'])
self.__dict__.update(d)

关于在 Windows 中使用多处理进行 Python 日志记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26167873/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com