我有一个相当大的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。但是,记录器无法被pickled。我尝试使用
__getstate__ 和 __setstate__ 避免pickling,并通过名称在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__'的记录器
或任何其他错误消息。我已经四处寻找了解如何完全重构我的程序中的日志记录方式的方法,但这显然是最后的手段。我希望我只是错过了一些明显的东西,希望群众的智慧能指出给我。
if key in some_dict.keys()
正是执行该检查的错误方式。在Python2中,它需要O(n)时间。只需使用if key in some_dict
。关于您的问题。子进程可能具有不同的标准输出,因此您看不到输出。尝试添加一个文件处理程序并检查文件中的输出是否正确。 - Bakuriu__init__
。这意味着子进程没有调用logging.config.dictConfig(...)
,因此可能正在使用默认配置。尝试更改__setstate__
方法,以便它使用正确的设置调用dictConfig
,看看是否有所改变。 - Bakuriu