Bagaimana cara memperbarui anggota kelas dalam proses? [duplikat]

Dec 26 2020

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

2 martineau Dec 27 2020 at 21:28

Anda bisa mendapatkan versi khusus dari Proxykelas yang digunakan oleh multiprocessing.BaseManagerdari (tidak berdokumen) multiprocessing.managers.NamespaceProxyyang, 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()