我有一个相当大的 Python 项目,目前在 Linux 上运行,但我正在尝试扩展到 Windows。我已将代码简化为一个完整的示例,可以运行它来说明我的问题:我有两个类,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)上,它会失败并出现酸洗错误:
C:\>python test.py
<snip>
pickle.PicklingError: Can't pickle <type 'thread.lock'>: it's not found as thread.lock
问题归结为 Windows 缺乏真正的分叉,因此在线程之间发送对象时必须进行 pickle。但是,记录器不能被腌制。我尝试过使用__getstate__
and __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:\>
尽管没有消息抱怨,但孩子似乎无法使用记录器No logger could be found for handler '__main__'
或任何其他错误消息。我环顾四周,发现有一些方法可以完全重组我登录程序的方式,但这显然是最后的手段。我希望我只是错过了一些明显的东西,希望群众的智慧能够向我指出这一点。