You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

关于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

火山引擎 最新活动