Como posso atualizar os membros da classe nos processos? [duplicado]
Procurei outras perguntas, e essa pergunta não aceita e respondida é a única que encontrei que de alguma forma cobre esse problema e não é realmente útil. Além disso, preciso disso para trabalhar com processos, não com threads.
Então, desde o início, escrevi um programa de amostra para mostrar meu problema, você deve ser capaz de colá-lo e ele executará:
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
Isso me diz que ou a maçã está em uma suposição estranha onde tem duas cores ao mesmo tempo, OU que a maçã new_process 'está em outra posição no carneiro e separada da maçã no processo principal.
Portanto, a pergunta é: existe uma maneira de fazer com que o ponteiro da maçã no processo aponte para a mesma maçã, ou qual é a maneira pítônica de manter todas as instâncias da maçã em todos os processos iguais? E se eu tiver a mesma maçã em muitos processos e ainda mais processos sem a maçã, como posso ter certeza de que eles serão sempre iguais?
Respostas
Você pode derivar uma versão especializada de uma Proxy
classe usada por multiprocessing.BaseManager
um (não documentado) multiprocessing.managers.NamespaceProxy
que, ao contrário da classe base, expõe todos os seus métodos e atributos. Isso é semelhante à resposta de @ shtse8 à pergunta duplicada vinculada, mas estou postando para deixar claro como fazer isso.
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()