处理 HDF5 文件中大量大型二维数组的建议(最佳实践)

Advice (Best practices) for handling large number of large 2D arrays in HDF5 files

我正在使用 python 程序将 4000x4000 数组写入 hdf5 文件。 然后,我通过一个 c 程序读取数据,我需要它作为输入来进行一些模拟。我需要这些 4000x4000 阵列中的大约 1000 个(意思是,我正在进行 1000 次模拟运行)。

我现在的问题如下:"better"、1000 个单独的 hdf5 文件或一个包含 1000 个不同数据集(名为 'dataset_%04d')的大 hdf5 文件是哪条路?

非常感谢针对此类问题的任何建议或最佳实践行为(因为我不太熟悉 hdf5)。


以防万一,这很有趣,这是我用来编写 hdf5 文件的 python 代码:

import h5py
h5f = h5py.File( 'data_0001.h5', 'w' )
h5f.create_dataset( 'dataset_1', data=myData )
h5f.close

这真的很有趣,因为我目前正在处理类似的问题。

表现

为了更深入地调查问题,我创建了以下文件

import h5py
import numpy as np

def one_file(shape=(4000, 4000), n=1000):
    h5f = h5py.File('data.h5', 'w')

    for i in xrange(n):
        dataset = np.random.random(shape)
        dataset_name = 'dataset_{:08d}'.format(i)
        h5f.create_dataset(dataset_name, data=dataset)
        print i

    h5f.close()


def more_files(shape=(4000, 4000), n=1000):

    for i in xrange(n):
        file_name = 'data_{:08d}'.format(i)
        h5f = h5py.File(file_name, 'w')
        dataset = np.random.random(shape)
        h5f.create_dataset('dataset', data=dataset)
        h5f.close()
        print i

然后,在IPython、

>>> from testing import one_file, more_files
>>> %timeit one_file(n=25) # with n=25, the resulting file is 3.0GB
1 loops, best of 3: 42.5 s per loop
>>> %timeit more_files(n=25)
1 loops, best of 3: 41.7 s per loop

>>> %timeit one_file(n=250)
1 loops, best of 3: 7min 29s per loop
>>> %timeit more_files(n=250)
1 loops, best of 3: 8min 10s per loop

这种差异让我感到非常惊讶,因为 n=25 拥有更多文件会更快,但是对于更多数据集来说这不再是事实。

经验

正如其他人在评论中指出的那样,可能没有正确答案,因为这是非常具体的问题。我为等离子体物理学研究处理 hdf5 文件。我不知道它是否对你有帮助,但我可以分享我的 hdf5 经验。

我运行 大量模拟和给定模拟的输出用于转到一个 hdf5 文件。模拟完成后,它会将其状态转储到此 hdf5 文件中,因此稍后我可以获取此状态并从该点扩展模拟(我也可以更改一些参数,我不需要从头开始)。该模拟的输出再次进入同一个文件。这太棒了——我只有一个文件用于一次模拟。但是,这种方法有一些缺点:

  1. 当模拟崩溃时,您最终得到的文件不是 'complete' - 您无法从该文件开始新的模拟。
  2. 没有简单的方法可以在另一个进程写入 hdf5 文件时安全地查看该文件。如果碰巧您尝试读取而另一个进程正在写入,您最终会损坏文件并且所有数据都将丢失!
  3. 我不知道有什么简单的方法可以从文件中删除组(如果有人知道方法,请告诉我)。因此,如果我需要重组文件,我需要从中创建新文件 (h5copyh5repack、...)。

所以我最终采用了这种效果更好的方法:

  1. 我定期从模拟中刷新状态,然后写入新文件。如果模拟崩溃,我只需要删除最后一个文件就不会浪费那么多 cpu 时间。
  2. 我目前只绘制除最后一个文件以外的所有文件的数据。请注意,还有另一种方法:参见 here,但我的方法绝对更简单,我同意。
  3. 处理更多的小文件比处理一个大文件要好得多 - 你会看到进度等等。

希望对您有所帮助。

聚会有点晚了,我知道,但我想我会分享我的经验。我的数据量较小,但从分析简单的角度来看,我实际上更喜欢一个大型(1000、4000、4000)数据集。在您的情况下,看起来您需要使用 maxshape 属性 使其在创建新结果时可扩展。保存多个单独的数据集使得很难跨数据集查看趋势,因为您必须将它们全部单独切片。使用一个数据集,您可以做例如。 data[:, 5, 20] 跨第三轴查看。此外,为了解决损坏问题,我强烈建议使用 h5py.File 作为上下文管理器:

with h5py.File('myfilename') as f:
    f.create_dataset('mydata', data=data, maxshape=(1000, 4000, 4000))

即使出现异常也会自动关闭文件。我曾经因为数据损坏而不停地咒骂,然后我开始这样做,从那以后就再也没有遇到过问题。