【问题标题】:Get Group Names for Massive HDF5 File获取海量 HDF5 文件的组名
【发布时间】:2020-04-27 07:21:51
【问题描述】:

我有可能超过 50 Gb 的 HDF5 文件。我只对获取顶级组之一中所有组的名称感兴趣。例如,

f = h5py.File('my_file.hdf')
names = f['top_level_group'].keys()

有超过 1,000,000 个组,运行上述代码需要数小时才能完成。有没有办法在合理的时间内做到这一点?我觉得简单地获取所有组的名称应该不会超过几秒钟。

编辑

我的实际生产代码是 C++ 并使用 C++ hdf5 API,其中包括函数GetObjnameByIdx()。这让我可以计算读取每个单独的组名并输出到日志文件所需的时间。我在周末让它运行,代码仍然没有完成。到目前为止,我的计时结果如下:

起初,代码以每组大约 1-1.5 毫秒开始。这对我来说似乎很慢,因为这意味着阅读所有组大约需要 30-35 分钟。无论如何,不​​久之后,它是 2 毫秒(此时,我周末回家,想在星期一之前得到完整的图表)。

Lo',我错了。请注意,这是一个半对数图,对数形状实际上代表线性趋势。有趣的是,在某些时候,它突然从每次读取 10 毫秒跃升至每次读取 2.5 秒(跳跃时间高达 25 秒!)。日志中的读取时间总和为 64.5 小时。

我无法在我生成的其他文件中重现此问题(不过,我们至少有 3 个生产文件存在此问题)。我生成的文件与有问题的生产文件具有相同的大小和结构,并且我使用生产代码中的相同功能生成了它们。加载这些测试文件需要 1-2 秒。

我知道文件并没有完全损坏,因为我们确实会得到结果,只要我们让它运行完成。数据就在那里,只是需要很长时间才能访问。

此时,由于我无法在测试文件中重现该问题,因此我的问题对于 StackOverflow 可能是无效的,但我完全不知道应该做什么。

【问题讨论】:

  • h5ls -r myfile.hdf 列出所有组需要多长时间?这给出了可能的下限的想法。
  • 从当前的打印速度推断,很可能需要一两个小时。但是,仅访问组名本身应该比打印出来要快几个数量级。
  • 尝试重定向到 /dev/null。 (h5ls -r myfile.hdf > /dev/null) 以排除打印和滚动的任何影响。
  • 41 分钟 /dev/null 重定向

标签: python c++ hdf5 h5py


【解决方案1】:

这很奇怪。获取组名/密钥不应该花费数小时。 除了访问群组之外,您还在做其他事情吗?

这是一个非常简单的示例,它创建 1,000,000 个组,关闭 HDF5 文件并重新打开以获取密钥。它在我的 Windows 笔记本电脑(24GB RAM)上运行一分钟左右。

with h5py.File('SO_59668177.h5','w') as h5f:
    for g_cnt in range(1000000):
        h5f.create_group('grp_' +str(g_cnt))

with h5py.File('SO_59668177.h5','r') as h5f:
    names = h5f.keys()
    print (len(names))

基于 OP 关于数据集的 cmets,我修改了上面的代码,为每个组添加一个数据集(加上一些定时输出)。然后我跑了不同的#s组(增加h5文件大小)。时序数据总结如下。请注意,对于 50GB 文件中的 1,000,000 个组(与 0.5GB 文件中的 10,000 个组相比),访问组/密钥的时间几乎没有变化。但是,还有其他性能瓶颈(如名称长度计数所示)。

10,000 个组 (0.5GB)
创建组和数据的时间 = 4.13
访问组的时间 = 0.000831
计数组的时间= 0.0227

100,000 个组 (5GB)
创建组和数据的时间 = 44.88
访问组的时间 = 0.000678
计数组的时间 = 0.266

1,000,000 个组 (50GB)
创建组和数据的时间 = 983.8
访问组的时间 = 0.00109
计数组的时间 = 724.9

修改后的代码如下。

size = 1000000
dim=80
arr=np.random.rand(dim*dim,1).reshape(dim,dim)

start = time.clock()
with h5py.File('SO_59668177.h5','w') as h5f:
    for g_cnt in range(size):
        grp=h5f.create_group('grp_' +str(g_cnt))
        grp.create_dataset('dset_1',data=arr)
print ('create groups and data')
print ('Elapsed time =', (time.clock() - start) )

start = time.clock() 
with h5py.File('SO_59668177.h5','r') as h5f:
    names = h5f.keys()
    print ('access groups')
    print ('Elapsed time =', (time.clock() - start) )

    start = time.clock() 
    print (len(names))
    print ('count groups')
    print ('Elapsed time =', (time.clock() - start) )

【讨论】:

  • 一分钟似乎仍然很荒谬,不是吗?无论如何,我猜你为什么只需要大约一分钟是因为文件中没有 50 Gb 的数据。
  • 如果您删除 print 语句,它实际上只需一两秒即可加载
  • 取决于您的比较。 :) 我尝试使用 HDF 查看器(用 Java 编写)打开我的示例文件,但它仍在尝试显示(6 分钟后)。
  • 我非常有信心阅读时间取决于每个组的大小。我的生产代码是用 C++ 编写的,它允许我一次读取单个组。我看到不同的子集(所有相同数量的组)根据组的大小加载不同的时间。
  • “删除打印语句”——并不奇怪。因此,在我的示例中,时间花在计算密钥上,而不是获取密钥上。下一个(修辞的)问题是:你有一个 50GB 的文件需要更长的时间吗?每组有多少个数据集?
猜你喜欢
  • 2021-11-14
  • 2021-08-30
  • 2021-03-27
  • 2023-03-28
  • 2016-04-17
  • 2017-10-24
  • 2016-11-17
  • 1970-01-01
  • 2018-02-19
相关资源
最近更新 更多