Comment puis-je mettre à jour les membres de la classe dans les processus? [dupliquer]

Dec 26 2020

J'ai cherché d'autres questions, et cette question sans réponse est la seule que j'ai pu trouver qui couvre en quelque sorte cette question et n'est pas vraiment utile. De plus, j'en ai besoin pour travailler avec des processus et non avec des threads.

Donc, à partir de zéro, j'ai écrit un exemple de programme pour montrer mon problème, vous devriez pouvoir le coller et il fonctionnera:

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

Cela me dit que soit la pomme est dans une supposition étrange où elle est de deux couleurs en même temps, soit que la pomme de new_process est dans une autre position dans la RAM et séparée de la pomme dans le processus principal.

La question est donc la suivante: y a-t-il un moyen pour que le pointeur de la pomme dans le processus pointe vers la même pomme, ou quelle est la manière pythonique de garder toutes les instances de la pomme dans tous les processus identiques? Et si j'ai la même pomme dans de nombreux processus et encore plus de processus sans la pomme, comment puis-je m'assurer qu'ils ont toujours la même surface?

Réponses

2 martineau Dec 27 2020 at 21:28

Vous pouvez dériver une version spécialisée d'une Proxyclasse utilisée par à multiprocessing.BaseManagerpartir d'un (non documenté) multiprocessing.managers.NamespaceProxyqui, contrairement à la classe de base, expose toutes ses méthodes et attributs. Ceci est similaire à la réponse de @ shtse8 à la question en double liée, mais je la poste pour expliquer clairement comment le faire.

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()