【问题标题】:How to change property of class object in another process/thread?如何在另一个进程/线程中更改类对象的属性?
【发布时间】:2022-01-02 16:57:10
【问题描述】:

例如,我有一个 Event 类,看起来像

class Event:
    def __init__(self):
        self.events = dict()

    def on(self, name, callback):
        self.events[name] = callback

    def emit(self, name):
        callback = self.events[name]
        if callable(callback):
            callback()

当我尝试在主线程中使用它时,它可以工作。

if __name__ == "__main__":
    event = Event()
    event.on("hello", lambda: print("hello world"))
    event.emit("hello")  # OUTPUT: hello world

但是当我尝试在另一个进程中注册我的事件时,它并没有改变,而是同一个进程。我已经定义了两个函数,其中一个设置新事件,另一个发出该事件。然后在不同的进程上运行这些函数。

def soldier(e):
    e.on("hello", lambda: print("hello world"))

def officer(e):
    e.emit("hello")

if __name__ == "__main__":
    event = Event()

    process1 = Process(target=officer, args=(event,))
    process2 = Process(target=soldier, args=(event,))

    process1.start()
    process2.start()

    process1.join()
    process2.join()

预期结果与上面没有进程的示例相同,但由于第一个进程仅在其内部更改 event.events 的值,并且更改的值在进程外部不可见,因此出现错误。

如何在进程外查看自定义类对象的变化值?

【问题讨论】:

  • 进程和线程在这方面有很大的不同,所以答案取决于你问的是哪一个——否则你的问题就太宽泛了。
  • 只是我在线程上尝试过同样的方法,但对进程更感兴趣
  • 进程更复杂,因为它们每个都在自己的内存空间中运行,所以没有真正的全局变量可以“共享”(与线程不同)。有几种不同的解决方法,其中一种是使用协调并发访问资源的“代理”。例如,请参阅我对Working with deque object across multiple processes 的回答。

标签: python multiprocessing python-multithreading


【解决方案1】:

如果要使用Process,则需要使用管道、消息传递机制或某种方法在不同进程之间共享数据。每次启动一个进程(使用Process),数据都会被克隆,所以3个进程(主进程和创建的2个进程)中存在3个变量事件。

这里使用共享相同内存空间的轻进程线程更简单。在下面的示例中,变量事件是共享的。

import threading

class Event:
    def __init__(self):
        self.events = dict()

    def on(self, name, callback):
        self.events[name] = callback

    def emit(self, name):
        if name in self.events:
            callback = self.events[name]
            if callable(callback):
                callback()

def officer(e):
    e.on("hello", lambda: print("hello world"))

def soldier(e):
    e.emit("hello")

if __name__ == "__main__":
    event = Event()

    thread1 = threading.Thread(target=officer, args=(event,))
    thread2 = threading.Thread(target=soldier, args=(event,))

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()
    

此外,您还必须添加一个安全机制,以确保该条目在使用之前已被注册。线程(或进程)的创建顺序并不能保证代码的执行顺序相同。

【讨论】:

  • 感谢这个解决方案,但我想使用进程,那么如何在进程之间共享内存?
  • 如果你想使用多处理模块,你可以看看 Pipe 或 Queue 例如。您还可以使用“共享内存”方法。
  • Lock 在这种情况下没有帮助。但是shared_memory 可能会有所帮助。谢谢!
  • 对于线程,您需要使用Lock 来防止并发访问——你在回答中没有这样做——所以它没有正确地做事。
  • 该主题是关于在动态实体(线程或进程)之间共享数据。在答案中,我说线程之间不能保证执行顺序,需要一些同步机制。我刚刚在 emit() 中插入了一个对 self.events 的简单测试,以避免崩溃“关键错误”(不太可能,但理论上可能)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多