Python多进程中Pool.starmap与共享字典的正确使用与常见陷阱解析


Python多进程中Pool.starmap与共享字典的正确使用与常见陷阱解析

本文深入探讨了在python多进程编程中使用`multiprocessing.pool.starmap`结合`syncmanager.dict`时可能遇到的空结果问题。核心在于`zip`函数与空可迭代对象的行为,以及如何正确构造传递给`starmap`的参数列表。通过详细的代码示例和解释,文章展示了如何避免`zip`陷阱,并确保共享字典在多进程环境中被正确填充和访问,从而实现预期的并行计算和数据共享。

在Python多进程编程中,multiprocessing模块提供了强大的工具来利用多核CPU进行并行计算。Pool对象及其starmap方法常用于将一个函数应用于一组参数,而SyncManager则允许在不同进程间共享数据结构,如字典。然而,不当的参数构造方式可能导致意想不到的空结果。

Pool.starmap与共享字典的常见问题

考虑以下使用multiprocessing.Pool和SyncManager.dict的场景:

import multiprocessing as mp
from multiprocessing.managers import SyncManager

n_cores = mp.cpu_count()

def parallel_fn(job_n, cache):
    # 尝试将结果存入共享缓存
    cache['job_b'] = job_n # 这里的键名可能不是我们想要的
    return job_n

if __name__=="__main__":
    with SyncManager() as manager:
        shared_cache = manager.dict()

        # 尝试构造starmap的参数
        args = list(zip(range(n_cores), shared_cache))

        with mp.Pool(n_cores) as pool:
            result = pool.starmap(parallel_fn, args)
            print(f"Pool return: {result}")

        print(f"Shared dict after: {shared_cache}")

运行上述代码,我们可能会得到如下输出:

Pool return: []
Shared dict after: {}

尽管我们期望Pool返回n_cores个结果,并且shared_cache被填充,但实际结果却是空的。这表明parallel_fn根本没有被执行,或者说starmap接收到了一个空的参数列表。

问题根源分析:zip函数的行为

导致上述问题的主要原因是zip函数的行为。zip函数会聚合每个可迭代对象中对应位置的元素,并生成一个由这些元素组成的元组。它的关键特性是:当最短的可迭代对象被耗尽时,zip就会停止。

在我们的示例中,args = list(zip(range(n_cores), shared_cache))这一行是问题的症结所在。

  • range(n_cores)是一个长度为n_cores(例如,如果CPU有8核,则为8)的可迭代对象。
  • shared_cache是一个SyncManager.dict()对象,在初始化时是空的,其长度为0。

当zip函数接收到一个长度为8的range对象和一个长度为0的ProxyDict对象时,它会立即停止,因为shared_cache已经耗尽。因此,zip返回一个空的迭代器,list(zip(...))的结果自然就是一个空列表。

我们可以通过一个简单的例子来验证这一点:

NoCode NoCode

美团推出的零代码应用生成平台

NoCode 180 查看详情 NoCode
print(list(zip([1, 2, 3], dict()))) # 输出: []
print(list(zip(range(5), [])))      # 输出: []

由于args列表为空,pool.starmap自然不会执行任何任务,从而返回一个空列表,并且shared_cache也保持为空。

解决方案:正确构造starmap的参数

要解决这个问题,我们需要确保starmap接收到一个包含正确数量和结构参数的列表。最直接且推荐的方法是使用列表推导式来显式地构造参数列表。

同时,我们也注意到原始代码中parallel_fn内部将键固定为'job_b'。通常,我们希望将任务相关的标识符(例如job_n)作为键来存储数据,以避免不同任务覆盖相同键的值。

以下是修正后的代码:

import multiprocessing as mp
from multiprocessing.managers import SyncManager

n_cores = mp.cpu_count()

def parallel_fn(job_n, cache):
    """
    并行执行的函数,将任务编号和结果存入共享缓存。
    """
    # 将 job_n 作为键存储,而不是固定的 'job_b'
    cache[job_n] = job_n 
    print(f"Process {mp.current_process().name} processing job {job_n}")
    return job_n

if __name__=="__main__":
    with SyncManager() as manager:
        shared_cache = manager.dict()

        # 使用列表推导式正确构造starmap的参数
        # 每个元组包含一个任务编号和一个共享字典的引用
        args = [(n, shared_cache) for n in range(n_cores)]

        print(f"Constructed args for starmap: {args}")

        with mp.Pool(n_cores) as pool:
            print("Starting pool.starmap...")
            result = pool.starmap(parallel_fn, args)
            print(f"Pool return: {result}")

        print(f"Shared dict after: {shared_cache}")

运行修正后的代码(假设我的机器是8核),输出如下:

Constructed args for starmap: [(0, <DictProxy object at 0x...>), (1, <DictProxy object at 0x...>), (2, <DictProxy object at 0x...>), (3, <DictProxy object at 0x...>), (4, <DictProxy object at 0x...>), (5, <DictProxy object at 0x...>), (6, <DictProxy object at 0x...>), (7, <DictProxy object at 0x...>)]
Starting pool.starmap...
Process ForkPoolWorker-1 processing job 0
Process ForkPoolWorker-2 processing job 1
Process ForkPoolWorker-3 processing job 2
Process ForkPoolWorker-4 processing job 3
Process ForkPoolWorker-5 processing job 4
Process ForkPoolWorker-6 processing job 5
Process ForkPoolWorker-7 processing job 6
Process ForkPoolWorker-8 processing job 7
Pool return: [0, 1, 2, 3, 4, 5, 6, 7]
Shared dict after: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7}

从输出可以看出,args列表现在包含了n_cores个元组,每个元组都携带了任务编号和shared_cache的引用。parallel_fn被成功执行了n_cores次,pool.starmap返回了预期的结果列表,并且shared_cache也被正确地填充了数据。

总结与注意事项

  1. 理解zip函数行为:在使用zip函数组合多个可迭代对象时,务必注意其“最短可迭代对象决定长度”的特性。当其中一个输入是空的或很快耗尽时,zip的结果也会是空的。
  2. 正确构造starmap参数:当需要向starmap传递包含相同共享对象(如SyncManager.dict)的多个参数时,使用列表推导式是构造参数列表的清晰且可靠的方法:[(arg1, shared_obj), (arg2, shared_obj), ...]。
  3. 共享数据结构的使用:multiprocessing.managers.SyncManager提供的共享数据结构(如manager.dict()、manager.list())是实现进程间数据共享的关键。确保这些共享对象在所有进程中都能被正确引用和访问。
  4. 避免键冲突:在向共享字典写入数据时,如果每个进程都有自己的结果需要存储,应使用唯一的键来避免数据覆盖。将任务编号或其他唯一标识符作为键是常见的做法。

通过理解这些核心概念和避免常见陷阱,开发者可以更有效地利用Python的multiprocessing模块进行并行计算,并正确管理进程间的共享数据。

以上就是Python多进程中Pool.starmap与共享字典的正确使用与常见陷阱解析的详细内容,更多请关注其它相关文章!


# 工具  # 多核  # 浮点  # 多个  # 是一个  # 长度为  # 数据结构  # red  # 可迭代对象  # 常见问题  # proxy  # ai  # python  # 迭代  # 南安推广网站选哪家  # 抚州seo关键词优化  # 海外内容营销推广方式  # 常州的外贸营销推广公司  # pc网站优化排名软件  # 搜索关键词排名推荐e火11星  # 净水器网站推广  # 贵州网站建设路火锅  # 庄河网站关键词优化  # 米泉网站推广  # 自己的  # 为空  # 最短 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 《一起考教师》账号注销方法  Eclipse开发J*a快速入门  Windows Audio服务启动失败怎么办_电脑没声音的终极服务修复法【修复】  《百度畅听版》关闭兴趣推荐方法  Excel如何制作月度销售统计图_Excel动态图表制作与控件应用  CSS过渡与滚动滚动事件结合应用_scroll与transition动画  《真我》申请退款方法  《地下城堡4:骑士与破碎编年史》墓穴挑战125攻略  Animex动漫社正版在线入口 Animex动漫社动漫官方观看网  excel怎么制作考勤表 excel考勤模板与函数公式讲解  J*a中导出MySQL表为SQL脚本的两种方法  C++ virtual析构函数作用_C++基类虚析构函数防止内存泄漏  Windows 11怎么删除恢复分区_Windows 11使用Diskpart命令强行删除分区  在J*a中如何实现类的继承与方法重用_OOP继承方法重用技巧分享  《新三国志曹操传》游历事件袁尚突围攻略  视频号视频怎么免费保存到相册?保存到相册需要注意什么?  如何在CSS中使用过渡制作按钮边框渐变_border-color transition实现  使用document.execCommand实现Web文本编辑器加粗/取消加粗  苹果手机怎么合并照片_苹果手机合并多张照片的操作方法  以下哪一个是适应长期护理制度发展而设立的新职业  《星露谷物语》克林特好感度事件介绍  抖音赚钱快速入门_新手必看的抖音赚钱步骤  Win10显卡驱动安装失败怎么办 Win10使用DDU彻底卸载驱动【解决】  百度小说看书时如何翻页_百度小说手动翻页与自动翻页设置  如何在CSS中清除浮动解决背景颜色不包裹内容问题_clear after技巧  优化Flask模板中SQLAlchemy查询迭代标签:处理字符串空格问题  如何用mysql开发用户注册登录功能_mysql用户注册登录数据库设计  自定义你的VS Code状态栏,监控关键信息  虫虫助手如何更新游戏  《下一站江湖2》风神腿获取攻略  快递优选如何查优选物流_快递优选专属物流渠道查询与配送时效  sublime怎么快速在浏览器中预览HTML_sublime配置View in Browser教程  2025SNH48年度青春盛典门票价格及购买方式  圆通快递官网入口查询单号 手机版官方查询入口  PHP页面重载后变量状态保持:实现用户档案连续浏览的教程  传统曲艺莲花落的表演形式是  VBA Outlook邮件自动化:高效集成Excel数据与列标题的策略  123平台官方登录入口 123邮箱网页端在线沟通工具  《edge浏览器》关闭翻译功能方法  英雄联盟争者留名活动介绍  红手指专业版app注册教程  微星主板BIOS怎么调整内存时序_内存参数手动优化BIOS设置教程  《图怪兽》退出登录方法  银信通自动开通原因揭秘  Sublime怎么自动添加CSS前缀_Sublime安装Autoprefixer插件  鸿蒙单条备忘录如何加密  优化长HTML属性值:SonarQube警告与实用策略  网易云音乐闹钟铃声设置教程  国际经济与贸易就业方向解析  Python中安全地将环境变量转换为整数的类型注解指南 

 2025-11-24

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.