multiprocessing.Process下线程无法更新实例属性的问题求助
问题分析与解决方案
我希望并行运行多个Foo类实例,通过Redis更新实例的value属性。每个实例启动后台线程监听Redis变化,但执行redis-cli set value 9后,线程检测到变化并打印提示,但实例的value属性并未更新,run方法始终输出初始值5。
原代码:
import time import threading import redis class Foo: def __init__(self, name: str): self.name = name self.redis_client = redis.Redis(host="localhost", port=6379) self.value = 5 self.update_thread = threading.Thread(target=self.update, daemon=True) self.update_thread.start() def update(self): while True: new_value = int(self.redis_client.get("value")) if new_value != self.value: print("new value detected {}".format(new_value)) self.value = new_value time.sleep(2) def run(self): while True: print("{}: Value: {}".format(self.name, self.value)) time.sleep(2) if __name__ == "__main__": import multiprocessing foo1 = Foo(name="foo1") foo2 = Foo(name="foo2") process1 = multiprocessing.Process(target=foo1.run) process2 = multiprocessing.Process(target=foo2.run) process1.start() process2.start()
控制台输出:
foo1: Value: 5 foo2: Value: 5 new value detected 9 new value detected 9 foo1: Value: 5 foo2: Value: 5
问题根源
- 父进程创建foo1、foo2实例时,已在父进程中启动它们的update线程,这些线程仅在父进程内存空间运行,更新的是父进程中实例的value。
- 使用
multiprocessing.Process传递foo1.run时,Python会将父进程中的foo1实例序列化后复制到子进程,子进程得到的是完全独立的实例副本,与父进程实例的内存空间完全隔离。 - 子进程的实例副本不会继承父进程的update线程(反序列化过程不会重新执行
__init__中的线程启动逻辑),父进程的update线程也无法修改子进程副本的属性。 - 控制台中
new value detected 9是父进程里的update线程打印的,和子进程中的实例没有任何关系,子进程副本的value始终是初始的5。
解决方案
最直接的修复方式是让每个子进程独立创建Foo实例,这样每个子进程的实例会自己启动update线程,监听Redis并更新自身的value属性。
修改后的代码:
import time import threading import redis class Foo: def __init__(self, name: str): self.name = name self.redis_client = redis.Redis(host="localhost", port=6379) self.value = 5 self.update_thread = threading.Thread(target=self.update, daemon=True) self.update_thread.start() def update(self): while True: new_value = int(self.redis_client.get("value")) if new_value != self.value: print("new value detected {}".format(new_value)) self.value = new_value time.sleep(2) def run(self): while True: print("{}: Value: {}".format(self.name, self.value)) time.sleep(2) if __name__ == "__main__": import multiprocessing def start_foo(name): # 子进程内创建实例,启动自身的update线程 foo = Foo(name=name) foo.run() process1 = multiprocessing.Process(target=start_foo, args=("foo1",)) process2 = multiprocessing.Process(target=start_foo, args=("foo2",)) process1.start() process2.start()
效果验证
执行redis-cli set value 9后,控制台会输出:
foo1: Value: 5 foo2: Value: 5 new value detected 9 new value detected 9 foo1: Value: 9 foo2: Value: 9
此时每个子进程的实例都能正确更新value属性并打印最新值。
内容的提问来源于stack exchange,提问作者birdalugur
相关产品推荐
相关产品推荐

