关于multiprocessing Manager字典键的疑问:为何代码出现KeyError?
问题分析与解决方案
嘿,这个问题我之前也碰到过,咱们一步步来拆解:
为什么会出现KeyError?
你遇到的核心问题是:你在Namespace里初始化的是一个普通的Python字典{},而不是multiprocessing.Manager提供的进程安全代理字典。
multiprocessing.Manager的作用是创建能跨进程共享的对象,但普通字典是原生的非代理对象——当你把它赋值给ns.results_dict后,子进程访问这个属性时,拿到的其实是原字典的一份拷贝,而不是和主进程共享的同一个字典。这就导致:
- 子进程里对
namespace.results_dict[string] = string的操作,只是修改了子进程自己内存里的拷贝字典 - 主进程里的原字典根本没被修改,甚至在某些情况下,子进程里的拷贝可能因为跨进程序列化/反序列化的问题,出现状态不一致,最终抛出
KeyError
另外,Manager.Namespace本身是用来托管共享对象的,但它只对由Manager创建的代理对象提供跨进程同步支持,普通对象不在这个范围内。
怎么修复?
很简单,把普通字典换成Manager创建的代理字典mgr.dict()就行,修改后的代码如下:
import multiprocessing def f(string, namespace): namespace.results_dict[string] = string if __name__ == '__main__': mgr = multiprocessing.Manager() ns = mgr.Namespace() # 用Manager创建的代理字典替换普通字典 ns.results_dict = mgr.dict() p = multiprocessing.Process(target=f, args=('burger', ns,)) p.start() p.join() print(ns.results_dict) # 现在会正常输出: {'burger': 'burger'}
这样一来,ns.results_dict就是一个由Manager托管的进程安全代理对象,子进程对它的修改会同步到主进程,自然就不会出现KeyError了。
额外小提示
- 除了
dict(),Manager还提供了list()、Lock()、Queue()等一系列跨进程共享的对象类型,这些都是经过封装的代理对象,能保证进程间的同步访问 - 尽量避免在
Namespace里存放普通的可变对象,因为它们无法跨进程共享状态,很容易出现类似的同步问题
内容的提问来源于stack exchange,提问作者jsstuball




