You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多进程中Manager.dict()迭代时对象引用变化问题求助

问题描述

复现代码

from multiprocessing import Manager 

class myObject():
    #执行操作


manager = Manager() 
dictio = manager.dict()


dictio[(1)] = myObject() 
print (dictio[(1)])

dictio[(2)] = myObject() 
print (dictio[(2)])


for key,value in dictio.items():    
    print (value)    
    print (dictio[key])

print (dictio[(1)])
print (dictio[(2)])

exit()

打印结果

print ( dictio [(1)] )
object at 0x7f1dca56c850

print ( dictio [(2)] )
object at 0x7f1dca56c880

print ( dictio [key] )
object at 0x7f1dcac53af0
object at 0x7f1dca56c130

print ( value )
object at 0x7f1dca56c550
object at 0x7f1dca56c550

print ( dictio [(1)] )
object at 0x7f1dca56c850

print ( dictio [(2)] )
object at 0x7f1dca56c880

疑问

为何循环中print(value)和print(dictio[key])的对象引用,与直接print(dictio[(1)])、print(dictio[(2)])的引用不同?如何在迭代proxydict时保持对象引用一致?


原因与解决方案

原因

Manager.dict()创建的是代理字典(ProxyDict),它是跨进程通信的代理对象,而非本地普通字典。每次从代理字典中获取对象时,都会通过进程间通信把远程对象序列化/反序列化,返回一个全新的本地副本——这就是内存地址不同的核心原因:你拿到的不是同一个对象实例,而是每次操作生成的新副本。

直接通过dictio[(1)]取时地址看似不变,是因为代理对象内部做了短时间缓存,但迭代items()返回的value是直接反序列化的新副本,循环内再取dictio[key]又是一次新的反序列化操作,所以地址全部不一样。

解决方案

1. 将自定义类注册为可共享的代理对象

让自定义类继承multiprocessing.managers.BaseManager并注册,存入字典的就是对象的代理引用,而非序列化副本,每次获取都会指向同一个远程实例:

from multiprocessing.managers import SyncManager

class myObject():
    def __init__(self):
        self.data = 0
    def set_data(self, val):
        self.data = val
    def get_data(self):
        return self.data

# 注册自定义类到管理器
SyncManager.register('myObject', myObject)

if __name__ == '__main__':
    manager = SyncManager()
    manager.start()
    
    dictio = manager.dict()
    dictio[1] = manager.myObject()
    dictio[2] = manager.myObject()
    
    print(dictio[1])
    print(dictio[2])
    
    for key, value in dictio.items():
        print(value)
        print(dictio[key])
        # 验证引用一致:修改value的属性,dictio[key]同步变化
        value.set_data(key*10)
        print(dictio[key].get_data())
    
    print(dictio[1])
    print(dictio[2])

这种方式下,所有获取到的value和dictio[key]都是指向同一远程对象的代理,内存地址保持一致,且修改操作会跨进程同步。

2. 本地缓存代理字典中的对象

如果不想修改类结构,可在迭代前把所有对象一次性取到本地字典缓存,后续操作本地缓存的对象即可保证引用一致:

from multiprocessing import Manager 

class myObject():
    def __init__(self):
        self.id = id(self)

manager = Manager() 
dictio = manager.dict()

dictio[1] = myObject() 
print(dictio[1])

dictio[2] = myObject() 
print(dictio[2])

# 本地缓存所有对象,避免重复反序列化
local_cache = {k: dictio[k] for k in dictio}

for key, value in local_cache.items():    
    print(value)    
    print(local_cache[key])
    # 验证引用一致:id完全相同
    print(id(value) == id(local_cache[key]))

print(dictio[1])
print(dictio[2])

注意:这种方式下,本地缓存的是对象副本,修改本地对象不会同步到代理字典中,仅适用于无需跨进程同步的场景。


内容的提问来源于stack exchange,提问作者VaraZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:42:17