信息发布→ 登录 注册 退出

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

发布时间:2025-11-24

点击量:

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(...))的结果自然就是一个空列表。

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

PictoGraphic PictoGraphic

AI驱动的矢量插图库和插图生成平台

PictoGraphic 133 查看详情 PictoGraphic
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与共享字典的正确使用与常见陷阱解析的详细内容,更多请关注其它相关文章!


相关文章: Pyrogram与g4f集成:异步编程实践与常见错误解决  QQ邮箱网页版快速登录 QQ邮箱邮箱账号官方入口地址  C++20的source_location是什么_C++在编译期获取源码位置信息用于日志和断言  steam官方网页快速访问 steam账号注册全流程  在WordPress中通过REST API访问受BasicAuth保护的站点内容  html怎么运行外部js文件中的函数_运html外js文件函数法【技巧】  将PCM16音频转换为W*并编码为Base64:浏览器环境下的手动处理指南  Composer的 "licenses" 命令如何帮助你遵守开源协议_检查项目依赖的许可证合规性  LINUX怎么安装MySQL_LINUX数据库安装配置教程  PHP高效扁平化嵌套数组:使用array_merge与数组解包操作符  Bilibili动漫最新防封地址发布-Bilibili动漫2025年最稳正版入口推荐  圆通快递查询实时追踪 圆通物流包裹状态快速查看  SteamMachine定价或为699美元 大家想入手吗?  Golang如何实现容器化日志收集与分析_Golang容器日志收集分析方法  使用PHP从URL路径中提取倒数第二个片段  在FastAPI中利用lifespan与依赖注入高效管理Redis连接池  一加手机电池耗电快怎么办_一加手机电池耗电快的解决方法  Highcharts 雷达图径向轴标签定制指南:利用多Y轴实现数值标注  解决Django多数据库/多Schema环境下外键迁移问题  TikTok国际版网页端快速入口 TikTok全球版短视频浏览教程  如何使用Node.js csv 包按条件移除含空字段的CSV记录  mc.js游戏直达 mc.js网页免下载版本秒进地址  零跑汽车11月交付量达70327台 实现连续9个月正增长  智慧团建扫码登录入口 智慧团建扫码登录入口官网版​  蛙漫官方正版入口 蛙漫网页在线全集免费观看  C++如何检测键盘输入_C++ _kbhit与_getch函数非阻塞输入  漫蛙manwa2最新登录网址_漫蛙manwa2手机网页版入口  lar*el怎么安全地存储和获取配置文件中的敏感信息_lar*el敏感信息安全存储方法  CSS布局:解决全屏元素100%尺寸与外边距导致的页面溢出问题  Win10怎么制作U盘启动盘 Win10系统安装U盘制作教程【详解】  怎样更改Windows系统的默认安装路径_避免C盘爆满的终极设置【技巧】  谷歌浏览器最新官方入口链接 谷歌浏览器网页版官网导航  Android Studio计算器C键功能异常排查与修复教程  韩剧圈正版入口页面_韩剧圈官网登录链接  微信网页版官方快速登录入口 微信网页版网页版账号直达  三星GalaxyZFold5怎样在相册制作折叠屏分镜_iPhone三星GalaxyZFold5相册制作折叠屏分镜【创意编辑】  PowerPoint如何制作滚动字幕结尾彩蛋_PowerPoint路径动画实现平滑滚动字幕效果  火狐浏览器占用内存高卡顿怎么办 火狐浏览器性能优化设置技巧  PHP字符串中复杂变量插值的最佳实践与语法解析  LINUX的perf命令入门_LINUX官方性能分析工具的使用与解读  怎么在mac上运行html代码_mac运行html代码方法【指南】  GemBox Document HTML转PDF垂直文本渲染问题及解决方案  Python大型XML文件高效流式解析教程  J*aScript数据结构转换:将对象数组按类别分组  手机CPU怎么影响游戏体验_手机CPU对游戏性能的影响分析  Flexbox布局实践:实现粘性导航栏与底部固定页脚  邮政快递单号查询入口 邮政快递物流信息在线查询入口  J*aScript井字棋(Tic-Tac-Toe)核心交互逻辑实现教程  Mac怎么使用表情符号_Mac Emoji快捷键面板  如何在网页中实现特定地点的随机图片展示 

在线客服
服务热线

服务热线

4008988990

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!