После много исследований и испытаний я обнаружил, что «Менеджер» выполняет эту работу в некоммерческом уровне.
Код, показанный ниже, показывает, что объект inst
совместно используется между процессами, что означает, что свойство var
10 из inst
изменено снаружи, когда дочерний процесс меняет его.
from multiprocessing import Process, Manager
from multiprocessing.managers import BaseManager
class SimpleClass(object):
def __init__(self):
self.var = 0
def set(self, value):
self.var = value
def get(self):
return self.var
def change_obj_value(obj):
obj.set(100)
if __name__ == '__main__':
BaseManager.register('SimpleClass', SimpleClass)
manager = BaseManager()
manager.start()
inst = manager.SimpleClass()
p = Process(target=change_obj_value, args=[inst])
p.start()
p.join()
print inst # <__main__.SimpleClass object at 0x10cf82350>
print inst.get() # 100
Итак, выше код достаточно, если вам нужно только разделить простые объекты.
Почему нет комплекса? Поскольку может не сработать если объект вложен (объект внутри объекта):
from multiprocessing import Process, Manager
from multiprocessing.managers import BaseManager
class GetSetter(object):
def __init__(self):
self.var = None
def set(self, value):
self.var = value
def get(self):
return self.var
class ChildClass(GetSetter):
pass
class ParentClass(GetSetter):
def __init__(self):
self.child = ChildClass()
GetSetter.__init__(self)
def getChild(self):
return self.child
def change_obj_value(obj):
obj.set(100)
obj.getChild().set(100)
if __name__ == '__main__':
BaseManager.register('ParentClass', ParentClass)
manager = BaseManager()
manager.start()
inst2 = manager.ParentClass()
p2 = Process(target=change_obj_value, args=[inst2])
p2.start()
p2.join()
print inst2 # <__main__.ParentClass object at 0x10cf82350>
print inst2.getChild() # <__main__.ChildClass object at 0x10cf6dc50>
print inst2.get() # 100
#good!
print inst2.getChild().get() # None
#bad! you need to register child class too but there's almost no way to do it
#even if you did register child class, you may get PicklingError :)
Я думаю, что основная причина такого поведения в том, что Manager
просто моноблок надстройки средств связи низкого уровня, таких как трубы /очередь.
Итак, этот подход не рекомендуется для многопроцессорного чехла. Это всегда лучше, если вы можете использовать низкоуровневые средства, как блокировки/семафора/трубы/очереди или высокоуровневые инструменты, такие как очереди Redis или Redis публикации/подписки для сложного случая использования (только моя рекомендация лол).
related: http://stackoverflow.com/questions/659865/python-multiprocessing-sharing-a-large-read-only-object-between-processes – tokland