Wie kann ich Klassenmitglieder in Prozessen aktualisieren? [Duplikat]
Ich habe nach anderen Fragen gesucht, und diese nicht akzeptierte, beantwortete Frage ist die einzige, die ich finden konnte, die dieses Problem irgendwie abdeckt und nicht wirklich hilfreich ist. Außerdem brauche ich dies, um mit Prozessen und nicht mit Threads zu arbeiten.
Von Grund auf habe ich ein Beispielprogramm geschrieben, um mein Problem zu zeigen. Sie sollten es einfügen können und es wird ausgeführt:
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
Dies sagt mir, dass sich entweder der Apfel in einer seltsamen Annahme befindet, in der er gleichzeitig zwei Farben hat, oder dass sich der Apfel von new_process an einer anderen Position im RAM befindet und im Hauptprozess vom Apfel getrennt ist.
Die Frage ist also: Gibt es eine Möglichkeit, den Zeiger des Apfels im Prozess auf denselben Apfel zu verweisen, oder wie kann alle Instanzen des Apfels in allen Prozessen auf pythonische Weise gleich bleiben? Was ist, wenn ich in vielen Prozessen den gleichen Apfel habe und noch mehr Prozesse ohne den Apfel? Wie stelle ich sicher, dass sie immer gleich sind?
Antworten
Sie können eine spezielle Version einer Proxy
Klasse ableiten, die von multiprocessing.BaseManager
einer (nicht dokumentierten) Klasse verwendet wird multiprocessing.managers.NamespaceProxy
, die im Gegensatz zur Basisklasse alle ihre Methoden und Attribute verfügbar macht. Dies ähnelt der Antwort von @ shtse8 auf die verknüpfte doppelte Frage, aber ich poste sie, um zu verdeutlichen, wie es geht.
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()