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

4
我正在使用Python程序将一个4000x4000数组写入hdf5文件。然后,我通过C程序读取数据,并将其作为输入进行一些模拟。我需要大约1000个这样的4000x4000数组(意味着我要运行1000次模拟)。
我的问题是:哪种方式更好,是采用1000个单独的hdf5文件,还是一个大的hdf5文件,其中包含1000个不同的数据集(命名为 'dataset_%04d')?
对于这种问题,任何建议或最佳实践都会受到极大的赞赏(因为我对hdf5不太熟悉)。
以下是我正在使用的Python代码,用于编写hdf5文件:
import h5py
h5f = h5py.File( 'data_0001.h5', 'w' )
h5f.create_dataset( 'dataset_1', data=myData )
h5f.close

为什么不直接测试并告诉我们呢 ;) 我不确定是否有正确的答案。HDF5没有文件大小限制,因此,如果您的用例需要快速访问数据集,则将它们放入一个文件中可能是一个优势,这样可以避免打开文件所花费的时间(至少在HPD文件系统上,这个时间可能是相当显著的)。 - kakk11
目前我正在进行的工作是排序。我决定尝试一次单个大文件的方法,这应该会导致一个约40GB的文件大小。我的问题是想了解有经验的hdf5用户如何处理这个问题。从我在网上阅读的内容中,我得出的印象是这将是单文件方法。感谢您确认我对文件大小限制的假设。 - Alf
2个回答

4

我觉得这很有趣,因为我现在正在处理类似的问题。

性能

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

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. 当模拟崩溃时,您会得到一个不完整的文件-您无法从该文件开始新的模拟。
  2. 当另一个进程正在写入该文件时,没有简单的方法可以安全地查看hdf5文件。如果尝试从中读取并且另一个进程正在写入,则会得到已损坏的文件,所有数据都会丢失!
  3. 我不知道是否有任何简单的方法可以从文件中删除组(如果有人知道,请告诉我)。因此,如果需要重新构造文件,则需要从中创建新文件(h5copyh5repack,...)。
因此,我最终采用了这种方法,它效果更好:
  1. 我定期从模拟中刷新状态,然后写入新文件。如果模拟崩溃,则只需删除最后一个文件即可,我不会浪费太多cpu时间。
  2. 我目前仅绘制除最后一个文件之外的所有文件的数据。请注意,还有另一种方法:请参见这里,但我的方法肯定更简单,我对此满意。
  3. 处理多个小文件比一个巨大的文件要好得多-您可以看到进展等等。
希望这有所帮助。

感谢您的回答@ziky。实际上,您不是唯一一个使用hdf5文件的等离子物理学家 ;)我决定采取以下措施:对于模拟的输入(基本上是网格),我使用一个大的hdf5文件(所有模拟都使用相同的文件)。目前它们是按顺序运行的(一个模拟,然后另一个模拟,依此类推),因此无法并行访问该文件 - 尽管我计划更改这种情况,让我们看看那时是否仍在工作。由于我还想在模拟期间访问结果,因此我决定每次运行都有一个输出文件(出于与您相同的原因)。 - Alf
听起来不错,@Alf。我也在使用并行访问h5文件,因为我的模拟是用Fortran + MPI编写的。我只使用Python处理结果。我认为你需要使用mpi进行文件的并行访问(但我可能错了)。我花了很多时间处理并行I/O例程。要能够仅从一个进程或同时从所有进程写入文件,这非常棘手。如果你有兴趣,让我知道,我可以分享更多经验。 - ziky

1
我知道我来晚了,但我想分享一下我的经验。虽然我的数据大小较小,但从分析的简单性角度来看,我实际上更喜欢一个大型数据集(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))

这将自动关闭文件,即使有异常情况。我曾因数据损坏而不断咒骂,后来开始使用这种方法,从此再也没有遇到过问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接