如何更新流程中的类成员?

Mar*_* Ge 6 python multiprocessing python-3.x python-multiprocessing

我寻找了其他问题,这个未接受的答案问题是我能找到的唯一一个以某种方式涵盖了这个问题并且没有真正帮助的问题。另外,我需要它来处理进程,而不是线程。

因此,我从头开始编写了一个示例程序来展示我的问题,您应该能够粘贴它并且它将运行:

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
Run Code Online (Sandbox Code Playgroud)
# actual output | # wanted output
red             | red
red             | red
new: brown      | new: brown
red             | brown
red             | brown
Run Code Online (Sandbox Code Playgroud)

这告诉我,要么苹果处于一个奇怪的假设,它同时有两种颜色,要么 new_process' 苹果位于 ram 中的另一个位置,并与主进程中的苹果分开。

所以问题是:有没有办法让进程中的苹果指针指向同一个苹果,或者什么是Pythonic方法来保持所有进程中苹果的所有实例相同?如果我在许多进程中有相同的苹果,甚至更多进程没有苹果,我如何确保它们始终相同?

mar*_*eau 6

您可以从(未记录的)类派生Proxy所使用的类的专用版本,该类与基类不同,公开其所有方法和属性。这类似于 @ shtse8对链接的重复问题的回答,但我在这里发布了一个可运行的答案,以明确它是如何完成的。multiprocessing.BaseManagermultiprocessing.managers.NamespaceProxy

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

Run Code Online (Sandbox Code Playgroud)