Bagaimana cara memperbarui anggota kelas dalam proses? [duplikat]
Saya telah mencari pertanyaan lain, dan pertanyaan yang tidak dapat dijawab ini adalah satu-satunya pertanyaan yang dapat saya temukan yang mencakup masalah ini dan tidak terlalu membantu. Juga, saya membutuhkan ini untuk bekerja dengan proses, dan bukan utas.
Jadi dari awal saya menulis program contoh untuk menunjukkan masalah saya, Anda harus dapat menempelkannya dan program itu akan berjalan:
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
Ini memberi tahu saya bahwa apel berada dalam anggapan aneh di mana itu adalah dua warna pada saat yang sama, ATAU apel new_process 'berada di posisi lain di ram dan terpisah dari apel di proses utama.
Jadi pertanyaannya adalah: Apakah ada cara agar penunjuk apel dalam proses mengarah ke apel yang sama, atau apakah cara pythonic untuk menjaga agar semua contoh apel dalam semua proses tetap sama? Bagaimana jika saya memiliki apel yang sama dalam banyak proses dan bahkan lebih banyak proses tanpa apel, bagaimana cara memastikan luasnya selalu sama?
Jawaban
Anda bisa mendapatkan versi khusus dari Proxy
kelas yang digunakan oleh multiprocessing.BaseManager
dari (tidak berdokumen) multiprocessing.managers.NamespaceProxy
yang, tidak seperti kelas dasar, mengekspos semua metode dan atributnya. Ini mirip dengan jawaban @ shtse8 untuk pertanyaan duplikat yang ditautkan, tetapi saya mempostingnya untuk memperjelas cara melakukannya.
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()