Python3.9 multiprocessing.imap_unordered随机报字典迭代修改错误
关于Python multiprocessing.Pool.imap_unordered偶发RuntimeError的问题分析
问题背景
- 在Python 3.9.7中使用
multiprocessing.Pool.imap_unordered时,随机抛出RuntimeError: dictionary changed size during iteration错误,偶发且多数运行正常 - 最初
getIterations()是生成器,改为返回完整列表后问题仍存在 - 调小chunksize至64以下可降低报错频率,但会导致运行速度变慢
- 曾尝试用
multiprocessing.Lock保护字典resultByKey的修改,依然报错,原以为结果处理循环是串行执行的 - 改用先收集所有结果到列表、再统一处理字典的方案后,问题解决
错误根源
你遇到的问题核心并非进程间同步问题,而是主进程内处理结果时,在遍历字典resultByKey的同时修改了它的大小,触发了Python字典的迭代保护机制。
具体来说:
multiprocessing.Lock是用于进程间的同步,而你的字典修改操作都在主进程内,这个锁完全起不到作用——主进程内的线程同步需要用threading.Lock,但这里根本不是多线程并发修改的问题。- 原代码的结果处理逻辑中,大概率存在这样的场景:在处理某个任务结果时,会遍历
resultByKey(比如检查已有键、合并数据),同时又往字典里新增键值对。Python的字典在迭代过程中不允许修改自身大小(增删键),一旦触发就会抛出RuntimeError。 - 报错的偶发性和chunksize相关:chunksize越大,子进程返回结果的批次越集中,主进程短时间内处理大量结果时,更容易出现“遍历字典+修改字典”的重叠场景;调小chunksize后结果分散,触发概率降低,但处理效率也随之下降。
新方案生效的原因
先收集所有结果到列表,再统一处理字典的逻辑,从根本上避免了“遍历字典的同时修改其大小”的情况:
- 收集结果阶段只是把所有任务产出的结果暂存到列表,完全不碰字典,自然不会触发迭代冲突。
- 统一处理字典时,你可以先遍历结果列表,逐个更新字典;或者先整理好所有需要新增/修改的键值对,再批量更新字典。无论哪种方式,都不会出现“正在迭代字典,同时又修改它的大小”的操作,彻底避开了Python字典的迭代保护限制。
内容的提问来源于stack exchange,提问作者kalelien
相关产品推荐
相关产品推荐

