全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Python多进程编程中zip函数与共享内存字典的常见陷阱解析

本文深入探讨了python多进程编程中一个常见的陷阱:当使用multiprocessing.pool.starmap配合zip函数来传递参数,并且其中一个参数是初始为空的multiprocessing.managers.syncmanager.dict时,可能导致任务无法执行。文章详细解释了zip函数的工作原理,揭示了问题根源,并提供了正确的参数构造方法,以确保多进程任务能有效利用共享数据并返回预期结果。

在Python中,多进程(multiprocessing)是实现并行计算的强大工具。当需要多个进程访问和修改同一份数据时,multiprocessing.managers.SyncManager提供的共享数据结构(如SyncManager.dict)变得尤为重要。然而,在使用这些工具时,一些看似细微的编码习惯可能会导致程序行为异常,甚至无法执行预期任务。

问题场景描述

考虑以下使用multiprocessing.Pool进行并行计算的场景,其中尝试通过starmap将任务编号和一个共享字典传递给每个子进程:

import multiprocessing as mp
from multiprocessing.managers import SyncManager

n_cores = mp.cpu_count()

def parallel_fn(job_n, cache):
    # 尝试将job_n作为键和值存入共享字典
    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: {}

预期的结果是result列表中包含n_cores个任务的返回值,并且shared_cache中也应存储了相应的数据。然而,实际输出显示Pool返回了一个空列表,共享字典也保持为空。这意味着parallel_fn函数根本没有被执行。

问题根源分析:zip函数的工作原理

造成上述问题的原因并非多进程本身,而是zip函数的一个关键特性。zip函数用于将多个可迭代对象打包成一个元组的迭代器,其核心行为是:当任何一个输入的可迭代对象耗尽时,zip函数就会停止生成元素。

在原始代码中,args的构造方式是:

args = list(zip(range(n_cores), shared_cache))

这里,range(n_cores)是一个长度为n_cores的可迭代对象。然而,shared_cache是一个通过SyncManager创建的ProxyDict对象,它在初始化时是空的。当zip函数尝试将range(n_cores)和shared_cache打包时,它会发现shared_cache(作为可迭代对象时,表示其键的迭代器)是空的。根据zip的规则,一旦遇到空的输入可迭代对象,它就会立即停止,因此list(zip(...))的结果就是一个空列表。

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

print(list(zip([1, 2, 3], dict()))) # 输出: []
print(list(zip(range(5), [])))      # 输出: []

因此,pool.starmap接收到的args列表实际上是空的,导致没有任何任务被分派到子进程执行。

此外,原始代码中parallel_fn内部将键固定为'job_b':cache['job_b'] = job_n。如果我们的目标是让每个任务将其自己的job_n作为键存储,那么这种固定键的方式是不合适的。

解决方案

要解决这个问题,我们需要确保starmap接收到的args列表包含正确数量的元组,每个元组都包含job_n和共享字典的引用。最直接且推荐的方法是使用列表推导式(list comprehension)来构造args:

import multiprocessing as mp
from multiprocessing.managers import SyncManager

n_cores = mp.cpu_count()

def parallel_fn(job_n, cache):
    # 将job_n作为键和值存入共享字典,更符合逻辑
    cache[job_n] = job_n 
    return job_n

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

        # 使用列表推导式构造starmap的参数
        # 确保每个任务都能获得job_n和shared_cache的引用
        args = [(n, shared_cache) for n in range(n_cores)]

        print(f"Arguments for starmap: {args}") # 打印以验证args内容

        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}")

修正后的代码与预期输出

在修正后的代码中,args列表将明确包含n_cores个元组,每个元组的第一个元素是任务编号n,第二个元素是shared_cache的引用。这样,starmap就能正确地将任务分发给子进程。

在我的8核机器上运行此代码,输出如下:

Arguments for starmap: [(0, ), (1, ), ..., (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}

可以看到,Pool返回了预期的结果,并且shared_cache也成功地存储了每个进程写入的数据。

关键注意事项与总结

  1. 理解zip函数行为: 在使用zip组合多个可迭代对象时,务必清楚其“最短原则”。如果其中一个可迭代对象为空,结果将是空的。这在构造多进程任务参数时尤其需要注意。
  2. 验证中间数据结构: 在将参数传递给多进程池之前,打印或检查中间变量(如本例中的args)是一个非常好的调试习惯,可以帮助快速定位问题。
  3. 共享数据结构的使用: multiprocessing.managers.SyncManager.dict在作为可迭代对象时,其行为与普通字典类似,即迭代其键。当它为空时,迭代结果也为空。
  4. 明确参数构造: 对于starmap这类需要接收参数元组序列的函数,使用列表推导式或循环来显式构造参数列表通常是更健壮和清晰的做法。
  5. 合理设计字典键: 在共享字典中存储数据时,选择有意义且能区分不同任务的键是最佳实践。将job_n作为键通常比使用固定字符串(如'job_b')更合理。

通过理解zip函数与SyncManager.dict在空状态下的交互行为,并采用正确的参数构造方法,我们可以避免多进程编程中的常见陷阱,确保并行任务能够高效、准确地执行。


# python  # 编码  # 工具  # ai  # proxy  # 可迭代对象  # red 


相关文章: 如何基于PHP生成高效IDC网络公司建站源码?  微信小程序制作网站有哪些,微信小程序需要做网站吗?  怎么用手机制作网站链接,dw怎么把手机适应页面变成网页?  实例解析angularjs的filter过滤器  制作网站的模板软件,网站怎么建设?  建站之星3.0如何解决常见操作问题?  如何快速重置建站主机并恢复默认配置?  建站之星各版本价格是多少?  阿里云网站制作公司,阿里云快速搭建网站好用吗?  上海制作企业网站有哪些,上海有哪些网站可以让企业免费发布招聘信息?  一键网站制作软件,义乌购一件代发流程?  制作企业网站建设方案,怎样建设一个公司网站?  如何在IIS服务器上快速部署高效网站?  广州营销型建站服务商推荐:技术优势与SEO优化解析  如何快速搭建高效香港服务器网站?  阿里云网站搭建费用解析:服务器价格与建站成本优化指南  定制建站策划方案_专业建站与网站建设方案一站式指南  Android自定义listview布局实现上拉加载下拉刷新功能  网站插件制作软件免费下载,网页视频怎么下到本地插件?  Thinkphp 中 distinct 的用法解析  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  台州网站建设制作公司,浙江手机无犯罪记录证明怎么开?  c++23 std::expected怎么用 c++优雅处理函数错误返回【详解】  电商网站制作价格怎么算,网上拍卖流程以及规则?  如何在阿里云虚拟主机上快速搭建个人网站?  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  图册素材网站设计制作软件,图册的导出方式有几种?  如何在Windows虚拟主机上快速搭建网站?  北京网站制作的公司有哪些,北京白云观官方网站?  网站app免费制作软件,能免费看各大网站视频的手机app?  高性价比服务器租赁——企业级配置与24小时运维服务  如何快速搭建虚拟主机网站?新手必看指南  专业制作网站的公司哪家好,建立一个公司网站的费用.有哪些部分,分别要多少钱?  如何高效利用亚马逊云主机搭建企业网站?  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  如何设计高效校园网站?  英语简历制作免费网站推荐,如何将简历翻译成英文?  大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?  建站之星展会模版如何一键下载生成?  宝塔建站后网页无法访问如何解决?  猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?  网站网页制作电话怎么打,怎样安装和使用钉钉软件免费打电话?  北京网站制作公司哪家好一点,北京租房网站有哪些?  网站制作费用多少钱,一个网站的运营,需要哪些费用?  公司网站的制作公司,企业网站制作基本流程有哪些?  linux top下的 minerd 木马清除方法  个人摄影网站制作流程,摄影爱好者都去什么网站?  沈阳制作网站公司排名,沈阳装饰协会官方网站?  如何快速搭建高效简练网站?  番禺网站制作公司哪家值得合作,番禺图书馆新馆开放了吗? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。