【发布时间】:2021-08-21 15:22:57
【问题描述】:
我们正在尝试将元类用于自定义后端选择(multiprocessing.Process 或 threading.Thread)。此实现背后的基本原理是扩展 Process/Thread 的功能以供我们自定义使用。虽然以下代码适用于fork(unix 中的默认值)。但是对于spawn(windows 中的默认值),我得到一个错误。
pickle.PicklingError: Can't pickle <class '__main__.DProcess'>: it's not the same object as __main__.DProcess
错误来自pickle module,因为对象不一样。
obj: <class '__main__.DProcess'>,
obj.__dict__: {'__module__': '__main__', 'run': <function DProcess.run at 0x7fa76ccd97a0>, '__doc__': None, '__slotnames__': []}
hash(obj): 5875061359185
obj2: <class '__main__.DProcess'>,
obj2.__dict__: {'__module__': '__main__', 'run': <function DProcess.run at 0x7fa76ccd97a0>, '__dict__': <attribute '__dict__' of 'DProcess' objects>, '__weakref__': <attribute '__weakref__' of 'DProcess' objects>, '__doc__': None},
hash(obj2): 5875061305336
我不太确定这里发生了什么。
- 为什么这两个对象不同?在类对象上从 pickle 模块执行
save_global不会失败。是因为__call__的实现吗?我该如何解决? - 为什么不为 fork 执行此检查?
代码如下:
class Backend(type):
_cache = {}
def __new__(cls, name, bases, dct):
_cls = super().__new__(cls, name, bases, dct)
# store the subclass dict to be used during __call__
Backend._cache.update(
{name: {'cls': cls, 'name': name, 'bases': bases, 'dct': dct}}
)
return _cls
def __call__(cls, *args, **kwargs) -> 'Backend':
try:
# check arg & select the base class
if args[0] == 'process':
import multiprocessing
_cls = multiprocessing.Process
elif args[0] == 'thread':
import threading
_cls = threading.Thread
except KeyError:
print('Please pass process or thread as the 1st arg')
for c in cls.mro()[-2::-1]:
# pick args from __new__ and call type()
arg_cls = Backend._cache[c.__name__]['cls']
arg_name = Backend._cache[c.__name__]['name']
arg_dct = Backend._cache[c.__name__]['dct']
_cls = super().__new__(arg_cls, arg_name, (_cls,), arg_dct)
return type.__call__(_cls, *args[1:], **kwargs)
class DProcess(metaclass=Backend):
def run(self):
print('we are in dprocess')
super().run()
if __name__ == '__main__':
from multiprocessing import set_start_method as _set_start_method
_set_start_method('spawn')
DProcess('process').start()
【问题讨论】:
标签: python multiprocessing pickle metaclass