如何解决h5py 的性能瓶颈在哪里?
我有一个带有 100 个“事件”的 HDF5。每个事件包含变量,但大约有 180 个称为“跟踪”的组,每个跟踪内部有 6 个数据集,这些数据集是 32 位浮点数的数组,每个大约 1000 个单元长(这在事件之间稍微进行,但在事件内部保持不变) .该文件是使用默认的 h5py 设置生成的(因此除非 h5py 自行完成,否则不会进行分块或压缩)。
读数不快。它比从 CERN ROOT TTrees 读取相同数据慢约 6 倍。我知道 HDF5 远不是市场上最快的格式,但如果您能告诉我速度丢失的地方,我将不胜感激。
要读取跟踪中的数组,我会这样做:
d0keys = data["Run_0"].keys()
for key_1 in d0keys:
if("Event_" in key_1):
d1 = data["Run_0"][key_1]
d1keys = d1.keys()
for key_2 in d1keys:
if("Traces_" in key_2):
d2 = d1[key_2]
v1,v2,v3,v4,v5,v6 = d2['SimSignal_X'][0],d2['SimSignal_Y'][0],d2['SimSignal_Z'][0],d2['SimEfield_X'][0],d2['SimEfield_Y'][0],d2['SimEfield_Z'][0]
行分析器显示,大约 97% 的时间花在最后一行。现在有两个问题:
- 读取单元格 [0] 和使用 [:] 读取所有 ~1000 个单元格之间似乎没有区别。我知道 h5py 应该能够从磁盘读取一块数据。为什么没有区别?
- 从 HDD(Linux、ext4)读取 100 个事件使用 h5py 需要约 30 秒,使用 ROOT 需要约 5 秒。 100 个事件的大小大约为 430 MB。这使 HDF 中的读出速度为 ~14 MBps,而 ROOT 为 ~86 MBps。两者都很慢,但 ROOT 更接近于我对大约 4 岁笔记本电脑硬盘的原始读取速度。
那么h5py在哪里失去速度?我想纯读数应该只是硬盘速度。因此,瓶颈是:
- 将 HDF5 地址解引用到数据集(ROOT 不需要这样做)?
- 在python中分配内存?
- 还有别的吗?
如果能提供一些线索,我将不胜感激。
解决方法
有很多 HDF5 I/O 问题需要考虑。我会尽量涵盖每一个。
根据我的测试,花费在 I/O 上的时间主要取决于读/写次数,而不是您读/写的数据量(以 MB 为单位)。阅读此 SO 帖子以了解更多详细信息:
pytables writes much faster than h5py. Why? 注意:它显示了 h5py 和 PyTables 具有不同 I/O 写入大小的固定数据量的 I/O 性能。基于此,大部分时间都花在最后一行是有道理的——那是您将数据从磁盘读取到内存作为 NumPy 数组 (v1,v2,v3,v4,v5,v6
) 的地方。
关于您的问题:
- 阅读
d2['SimSignal_X'][0]
和d2['SimSignal_X'][:]
之间没有区别是有原因的。两者都将整个数据集读入内存(所有 ~1000 个数据集值)。如果只想读取数据的切片,则需要使用切片表示法。例如,d2['SimSignal_X'][0:100]
只读取前 100 个值(假设d2['SimSignal_X']
只有一个轴 -shape=(1000,)
)。笔记;读取切片会减少所需的内存,但不会改善 I/O 读取时间。 (实际上,读取切片可能会增加读取时间。) - 我不熟悉 CERN ROOT,因此无法评论 h5py 与 ROOT 的性能。如果您想使用 Python,需要考虑以下几点:
- 您正在将 HDF5 数据读入内存(作为 NumPy 数组)。你不必那样做。您可以创建 h5py 数据集对象,而不是创建数组。这最初减少了 I/O。然后你使用对象“好像”它们是 np.arrays。唯一的变化是你的最后一行代码——像这样:
v1,v6 = d2['SimSignal_X'],d2['SimSignal_Y'],d2['SimSignal_Z'],d2['SimEfield_X'],d2['SimEfield_Y'],d2['SimEfield_Z']
。请注意如何不使用切片符号([0]
或[:]
)。 - 我发现 PyTables 比 h5py 更快。您的代码可以轻松转换为使用 PyTables 读取。
- HDF5 可以使用“分块”来提高 I/O 性能。你没有说你是否在使用这个。它可能会有所帮助(很难说,因为您的数据集不是很大)。您必须在创建 HDF5 文件时定义它,因此在您的情况下可能没有用。
- 您也没有说明写入数据时是否使用了压缩过滤器。这减少了磁盘文件大小,但具有降低 I/O 性能(增加读取时间)的副作用。如果您不知道,请检查是否在创建文件时启用了压缩。
- 您正在将 HDF5 数据读入内存(作为 NumPy 数组)。你不必那样做。您可以创建 h5py 数据集对象,而不是创建数组。这最初减少了 I/O。然后你使用对象“好像”它们是 np.arrays。唯一的变化是你的最后一行代码——像这样:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。