Después de mucha investigación y pruebas, encontré que el "Administrador" hace este trabajo en un nivel de objeto no complejo.
El código siguiente muestra que el objeto inst
se comparte entre procesos, lo que significa que la propiedad var
de inst
se cambia al exterior cuando el proceso hijo lo cambia.
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
bien, el código de seguridad es lo suficientemente si sólo necesita compartir objetos simples.
¿Por qué no hay complejos? Debido puede fallar si el objeto está anidado (objeto dentro de objeto):
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 :)
Creo que la razón principal de este comportamiento se debe a que Manager
es sólo un candybar construir en la parte superior de las herramientas de comunicación de bajo nivel como tubería /cola.
Por lo tanto, este enfoque es no bien recomendado para el caso de multiprocesamiento. Siempre es mejor si puede usar herramientas de bajo nivel como lock/semáforo/pipe/queue o herramientas de alto nivel como Redis queue o Redis publicar/suscribir para casos de uso complicado (solo mi recomendación jaja).
relacionado: http://stackoverflow.com/questions/659865/python-multiprocessing-sharing-a-large-read-only-object-between-processes – tokland