新闻中心
掌握mpi4py中不同形状数组的聚合操作

在使用mpi4py进行并行编程时,`comm.Gather`函数默认要求所有进程发送相同形状的数组,这在处理动态或异构数据时会引发问题。本文将深入探讨两种有效的解决方案:利用`comm.gather`(小写)聚合通用Python对象并进行后续拼接,以及使用更强大的`comm.Gatherv`函数直接将不同大小的数组聚合到一个预分配的NumPy缓冲区中,从而实现高效且灵活的数据收集。
mpi4py中不同形状数组聚合的挑战
在mpi4py中,MPI.COMM_WORLD.Gather()方法设计用于收集所有进程中形状和大小完全相同的NumPy数组到一个根进程上的单个NumPy数组中。它的工作原理是预设一个固定大小的接收缓冲区,因此,当各个进程发送的数组形状或元素数量不一致时,comm.Gather会因为无法匹配预期的缓冲区布局而失败。
例如,考虑以下场景,进程1发送一个形状为(2, 3)的数组,而其他进程发送形状为(5, 3)的数组:
from mpi4py import MPI
import numpy as np
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
# 模拟不同形状的数组
a = np.zeros((2 if rank == 1 else 5, 3), dtype=float) + rank
print(f"Rank {rank}: 数组形状 {a.shape}")
# comm.Gather 会在这里失败,因为它期望所有进程发送相同大小的数据
# b = np.zeros((12, 3), dtype=float) - 1 # 预分配一个足够大的缓冲区,但comm.Gather仍会因形状不匹配而失败
# comm.Gather(a, b, root=0)
# if rank == 0:
# print(b)为了解决这个问题,我们需要采用不同的聚合策略。
解决方案一:使用 comm.gather 聚合通用Python对象
comm.gather(注意小写)是comm.Gather的通用版本,它不限于处理NumPy数组,可以聚合任意Python对象。在根进程上,comm.gather会返回一个包含所有进程发送对象的列表(或元组)。对于不同形状的NumPy数组,这意味着根进程将收到一个由这些不同形状数组组成的列表,随后可以通过numpy.concatenate将其拼接成一个更大的数组。
示例代码
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
# 模拟不同形状的数组
a = np.zeros((2 if rank == 1 else 5, 3), dtype=float) + rank
print(f"Rank {rank}: 数组形状 {a.shape}, 数组内容:\n{a}")
# 使用 comm.gather 聚合数组
# 根进程会收到一个包含所有进程发送数组的列表
gathered_arrays = comm.gather(a, root=0)
if rank == 0:
# 根进程将收到的数组列表进行拼接
concatenated_array = np.concatenate(gathered_arrays)
print(f"\nRank {rank}: 聚合并拼接后的数组形状 {concatenated_array.shape}, 数组内容:\n{concatenated_array}")
else:
print(f"\nRank {rank}: 非根进程不接收聚合结果")
优点与考虑
- 简单易用: 对于任意Python对象都适用,无需关心底层数据类型或缓冲区细节。
- 灵活性高: 能够轻松处理不同形状、甚至不同类型的对象。
- 性能考量: 数据首先被包装成Python对象,然后在根进程上解包并进行NumPy拼接。对于非常大的数据集,这可能会引入额外的内存开销和计算时间,因为它涉及多次内存拷贝。
解决方案二:使用 comm.Gatherv 高效聚合变长数组
comm.Gatherv(注意大写V)是MPI中专门为聚合变长数据设计的函数。它允许每个进程发送不同数量的数据,并由根进程将其直接收集到一个预分配的NumPy数组缓冲区中。这避免了comm.gather中可能存在的额外Python对象处理和内存拷贝,因此通常在处理大型数值数据时更高效。
使用comm.Gatherv的关键在于正确配置接收缓冲区参数,这些参数以一个元组的形式提供:(recvbuf, counts, displacements, datatype)。
Moshi Chat
法国AI实验室Kyutai推出的端到端实时多模态AI语音模型,具备听、说、看的能力,不仅可以实时收听,还能进行自然对话。
160
查看详情
- recvbuf: 根进程上预先分配好的NumPy数组,用于接收所有进程的数据。其总大小必须足以容纳所有发送数据。
- counts: 一个列表或元组,指定从每个进程接收的元素数量。例如,如果进程0发送(5,3)的数组,则其元素数量为5*3=15。
- displacements: 一个列表或元组,指定从每个进程接收的数据在recvbuf中的起始偏移量(以元素数量计)。
- datatype: MPI数据类型,指定发送和接收元素的类型,例如MPI.DOUBLE对应NumPy的float64。
示例代码
为了简化示例,我们假设只有两个进程,一个发送(5, 3)的数组,另一个发送(2, 3)的数组。
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
# 确保进程数量不超过2,以便示例清晰
assert size <= 2, "此Gatherv示例仅为2个进程设计"
if rank == 0:
a = np.zeros((5, 3), dtype=float) + rank
else:
a = np.zeros((2, 3), dtype=float) + rank
print(f"Rank {rank}: 数组形状 {a.shape}, 数组内容:\n{a}")
# 计算全局总行数
# 对于 rank 0 (5行) 和 rank 1 (2行),总共 7 行
n_global_rows = 7
n_cols = a.shape[1] # 列数保持不变
# 根进程预分配接收缓冲区
if rank == 0:
b = np.zeros((n_global_rows, n_cols), dtype=float)
# 定义每个进程发送的元素数量 (行数 * 列数)
# 假设 rank 0 发送 5*3=15 个元素,rank 1 发送 2*3=6 个元素
send_counts = [5 * n_cols, 2 * n_cols]
# 定义每个进程数据在 b 中的起始偏移量 (以元素为单位)
# rank 0 的数据从 b[0] 开始 (0个元素偏移)
# rank 1 的数据从 b[5*n_cols] 开始 (15个元素偏移,即在 rank 0 数据之后)
displacements = [0, 5 * n_cols]
# 接收缓冲区描述符
recvbuf_params = (b, send_counts, displacements, MPI.DOUBLE)
else:
b = None # 非根进程不需要接收缓冲区,设为None
recvbuf_params = None # 非根进程也不需要接收缓冲区参数
# 执行 Gatherv 操作
comm.Gatherv(a, recvbuf_params, root=0)
if rank == 0:
print(f"\nRank {rank}: Gatherv 聚合后的数组形状 {b.shape}, 数组内容:\n{b}")
else:
print(f"\nRank {rank}: 非根进程不接收 Gatherv 结果")
优点与考虑
-
高效:
直接将数据聚合到预分配的NumPy缓冲区中,避免了不必要的内存拷贝和Python对象处理开销,尤其适用于大型数值数据集。 - 精确控制: 通过counts和displacements参数,可以精确控制每个进程发送的数据量及其在接收缓冲区中的位置。
- 复杂性: 需要手动计算每个进程发送的元素数量和在接收缓冲区中的偏移量,这在进程数量多或数据结构复杂时可能会变得繁琐且容易出错。
总结与选择建议
在mpi4py中处理不同形状的NumPy数组聚合时,您有以下两种主要选择:
-
comm.gather (小写):
- 适用场景: 当您需要聚合任意Python对象,或者数组形状差异较大且不规则,且对聚合性能要求不是极致时。
- 优点: 简单易用,代码直观。
- 缺点: 可能会引入额外的内存拷贝和Python对象处理开销。
-
comm.Gatherv (大写V):
- 适用场景: 当您处理大型数值NumPy数组,且对聚合性能有较高要求,希望直接将数据收集到预分配的缓冲区中时。
- 优点: 效率高,直接操作底层缓冲区,避免额外拷贝。
- 缺点: 配置相对复杂,需要手动计算每个进程的发送元素数量和偏移量。
选择哪种方法取决于您的具体需求:如果追求代码简洁和通用性,且数据量不大,comm.gather是更好的选择;如果数据量庞大,且对性能有严格要求,那么投入精力配置comm.Gatherv将是值得的。在实际应用中,通常会根据数据规模和性能瓶颈来决定最合适的聚合策略。
以上就是掌握mpi4py中不同形状数组的聚合操作的详细内容,更多请关注其它相关文章!
# 重启
# 付建 seo员
# 湖州市网站建设电话
# 贵阳网站建设的费用
# 农产品的推广及营销策略
# 网站优化哪个品牌好
# 新店开业营销渠道推广
# 合肥seo网络营销推广有限公司
# 淘宝seo每天更新时间
# 淮北全网营销推广找哪家
# 深圳坂田视频营销推广
# 易用
# python
# 这在
# 因为它
# 将其
# 两种
# 偏移量
# 数据结构
# 中不
# 区中
# red
# 性能瓶颈
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
蛙漫2日版入口 WAMAN2(日版)无删减漫画官网链接
C++如何实现一个智能指针_手动实现C++ shared_ptr的引用计数功能
拼多多购物车商品数量无法修改如何处理 拼多多购物车操作优化方法
俄罗斯Yandex免登录入口_Yandex搜索引擎官网一键直达
如何在低配置电脑上搭建轻量级J*a环境_占用更小的环境选择技巧
c++如何使用Meson构建系统_c++比CMake更快的构建工具
Go Martini框架:动态服务解码后的图片内容
MinIO大规模对象列表性能瓶颈深度解析与外部元数据管理策略
如何在Promise链中有效终止错误处理后的执行
Excel Power Pivot如何处理XML数据源 构建高级数据模型
地铁跑酷免费秒玩入口链接 地铁跑酷小游戏免费秒玩网站
Steam官网入口直达 Steam注册及登录步骤
NetBeans Ant项目:自动化将资源文件复制到dist目录的教程
蛙漫漫画官网在线入口 蛙漫全本漫画免费阅读平台
蛙漫2台版漫画地址 Manwa2正版网页版链接
小米14应用无法联网原因分析_小米14网络权限修复
支付宝如何管理隐私设置_支付宝隐私保护的配置技巧
Log4j Console Appender性能瓶颈与高并发优化策略
TikTok搜索不到用户发布内容怎么办 TikTok用户内容搜索优化方法
学习通在线学习平台 学习通网页版直接进入课程中心
理解J*aScript Promise的微任务队列与执行顺序
内存疯狂猛猛涨价:主板销量直接腰斩!
Python:递归比较文件夹内容并找出特定类型文件的差异
利用5118提升短视频内容效果_5118短视频关键词优化方法
Golang如何实现微服务鉴权与权限控制_Golang微服务鉴权与权限管理实践
印象笔记怎样用批量导出备知识库_印象笔记用批量导出备知识库【备份方法】
Win10快速启动功能利弊分析 Win10开启或关闭快速启动教程【技巧】
mysql密码锁定怎么解锁_mysql密码锁定解锁后修改密码步骤
漫蛙官网正版漫画入口 漫蛙2官方网页登录地址
php源码怎么在电脑上测试_电脑测试php源码方法步骤【教程】
lar*el怎么安全地存储和获取配置文件中的敏感信息_lar*el敏感信息安全存储方法
黑鲨3Pro怎样在相册开漫画风滤镜_iPhone黑鲨3Pro相册开漫画风滤镜【趣味滤镜】
React/Next.js中实现列表项的动态选择与移动
在Runstone环境中高效处理TasteDive API的JSON数据
J*aScript中安全有效地处理localStorage字符串数据
CSS如何设置hover状态颜色_hover伪类调整背景或文字颜色
Golang如何测试channel通信行为_Golang channel通信测试与分析方法
谷歌浏览器浏览体验优化_谷歌浏览器新版直连永久可用提示
在React函数组件中利用原生HTML5进行邮箱地址验证
怎样在Excel中做仪表盘_Excel仪表盘设计与关键指标展示方法
TikTok国际版网页端快速入口 TikTok全球版短视频浏览教程
Bing引擎入口最新2025 Bing搜索免费官方登录
Golang如何实现Web文件静态资源服务器_Golang静态资源服务器开发与实践
自定义Bag-of-Words实现:处理带负号的词汇权重
vivo手机参数配置怎么增强信号_vivo手机参数配置信号增强方法
在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析
QQ邮箱正确登录入口_QQ邮箱官方网站使用地址
QQ邮箱稳定登录入口_QQ邮箱官方网站网页版使用
Flexbox布局实践:实现粘性导航栏与底部固定页脚
qq邮箱发邮件给国外发不出去_QQ邮箱国际邮件发送失败原因与解决


2025-12-06
浏览次数:次
返回列表
直接将数据聚合到预分配的NumPy缓冲区中,避免了不必要的内存拷贝和Python对象处理开销,尤其适用于大型数值数据集。