Python多进程共享字典不生效,触发KeyError报错该如何解决?
问题原因
- multiprocessing.Manager创建的共享字典
manager.dict(),仅在对顶层键做直接赋值时会同步数据到所有进程。当你执行all_repo_data[(repo['name'])] = {}时,实际存入的是普通Python字典的副本,后续对这个内层字典的修改(比如all_repo_data[(repo['name'])]['stars'] = xxx)都只会修改本地内存里的副本,不会同步回共享字典,所以读取时就会找不到对应键触发KeyError。
解决方案
方案1:构造完整内层字典后一次性赋值(最推荐)
先把单个repo的所有字段都写入一个临时普通字典,再一次性赋值给共享字典的顶层键,修改后的fetch_repo_info代码如下:
def fetch_repo_info(all_repo_data, repos_data, total_stars,): for repo in repos_data: # 先构造完整的内层字典 repo_dict = {} repo_dict['name'] = repo repo_dict['id'] = repo['id'] repo_dict['stars'] = repo['stargazers_count'] repo_dict['commits_url'] = repo['commits_url'].split("{")[0] repo_dict['languages'] = repo['url'] + '/languages' repo_dict['contributors'] = repo['contributors_url'] # 一次性赋值给共享字典,触发同步 all_repo_data[repo['name']] = repo_dict total_stars += repo_dict['stars']
方案2:内层也使用共享字典
如果后续4个子进程还需要修改内层字典的字段,就把内层字典也改为Manager创建的共享字典:
def fetch_repo_info(all_repo_data, repos_data, total_stars, manager): # 额外传入manager实例 for repo in repos_data: # 内层也创建共享字典 repo_dict = manager.dict() repo_dict['name'] = repo repo_dict['id'] = repo['id'] repo_dict['stars'] = repo['stargazers_count'] repo_dict['commits_url'] = repo['commits_url'].split("{")[0] repo_dict['languages'] = repo['url'] + '/languages' repo_dict['contributors'] = repo['contributors_url'] all_repo_data[repo['name']] = repo_dict total_stars += repo_dict['stars']
调用时需要把manager实例传入函数:
fetch_repo_info(all_repo_data, repos_data, total_stars, manager)
额外注意事项
- 你当前代码里的
total_stars是普通整数,在函数内的赋值只会修改局部变量,不会影响外层的total_stars值,如果需要全局累计星数,要使用manager.Value('i', 0)来创建共享整数对象,修改时操作其value属性即可。 - 如果子进程也需要修改内层字典的字段,必须用方案2的嵌套共享字典,否则子进程的修改同样不会同步。
内容的提问来源于stack exchange,提问作者lex
相关产品推荐
相关产品推荐

