¿Cómo puedo actualizar a los miembros de la clase en los procesos? [duplicar]
He buscado otras preguntas, y esta pregunta no aceptada y respondida es la única que pude encontrar que de alguna manera cubre este problema y no es realmente útil. Además, necesito que esto funcione con procesos y no con subprocesos.
Entonces, desde cero, escribí un programa de muestra para mostrar mi problema, debería poder pegarlo y se ejecutará:
import multiprocessing
import time
class Apple:
def __init__(self, color):
self.color = color
def thinkAboutApple(apple):
while True:
print(apple.color)
time.sleep(2)
my_apple = Apple("red")
new_process = multiprocessing.Process(target=thinkAboutApple, args=(my_apple,))
new_process.start()
time.sleep(4)
print("new: brown")
my_apple.color = "brown"
#so that the program doesn't exit after time.sleep(4)
while True:
pass
# actual output | # wanted output
red | red
red | red
new: brown | new: brown
red | brown
red | brown
Esto me dice que la manzana está en una suposición extraña donde tiene dos colores al mismo tiempo, O que la manzana new_process 'está en otra posición en ram y separada de la manzana en el proceso principal.
Entonces, la pregunta es: ¿hay alguna manera de que el puntero de la manzana en el proceso apunte a la misma manzana, o cuál es la forma pitónica de mantener iguales todas las instancias de la manzana en todos los procesos? ¿Qué pasa si tengo la misma manzana en muchos procesos e incluso más procesos sin la manzana, cómo me aseguro de que sean siempre iguales?
Respuestas
Puede derivar una versión especializada de una Proxy
clase utilizada por multiprocessing.BaseManager
de un (no documentado) multiprocessing.managers.NamespaceProxy
que, a diferencia de la clase base, expone todos sus métodos y atributos. Esto es similar a la respuesta de @ shtse8 a la pregunta duplicada vinculada, pero la estoy publicando para dejar en claro cómo hacerlo.
from multiprocessing import Process
from multiprocessing.managers import BaseManager, NamespaceProxy
import time
import types
class MyManager(BaseManager): pass # Avoid namespace pollution.
class Apple:
def __init__(self, color):
self.color = color
def Proxy(target):
""" Create a derived NamespaceProxy class for `target`. """
def __getattr__(self, key):
result = self._callmethod('__getattribute__', (key,))
if isinstance(result, types.MethodType):
def wrapper(*args, **kwargs):
self._callmethod(key, args)
return wrapper
return result
dic = {'types': types, '__getattr__': __getattr__}
proxy_name = target.__name__ + "Proxy"
ProxyType = type(proxy_name, (NamespaceProxy,), dic) # Create subclass.
ProxyType._exposed_ = tuple(dir(target))
return ProxyType
AppleProxy = Proxy(Apple)
def thinkAboutApple(apple):
while True:
print(f"apple.color: {apple.color}")
time.sleep(1)
if __name__ == '__main__':
MyManager.register('Apple', Apple, AppleProxy)
manager = MyManager()
manager.start()
my_apple = manager.Apple("red")
new_process = Process(target=thinkAboutApple, args=(my_apple,))
new_process.start()
time.sleep(2) # Allow other process to run a short while.
my_apple.color = "brown" # Change shared class instance.
time.sleep(2) # Allow other process to run at little while longer.
new_process.terminate()