我有几个大的HDF5文件存储在SSD上(lzf压缩文件大小为10-15 GB,未压缩大小为20-25 GB)。将这样的文件中的内容读入RAM进行进一步处理每个文件大约需要2分钟。在此期间,仅使用一个核心(但是100%)。所以我想在CPU上运行的解压缩部分是瓶颈而不是SSD的IO吞吐量。
在我的程序开始时,它会将这种类型的多个文件读入RAM,这需要相当长的时间。我喜欢通过利用更多内核和最终更多内存来加速这一过程,直到SSD IO吞吐量成为限制因素。我正在研究的机器有足够的资源(20个CPU核心[+ 20 HT]和400 GB RAM)和“浪费”RAM并不是什么大问题,只要通过节省时间来证明这一点。
我自己有两个想法:
1)使用python的multiprocessing
模块并行读取多个文件到RAM中。这原则上是有效的,但由于在multiprocessing
中使用了Pickle(如here所述),我达到了4 GB的序列化限制:
OverflowError('无法序列化大于4 GiB的字节对象')。
2)制作几个进程(使用Pool
模块中的multiprocessing
)打开相同的HDF5文件(使用with h5py.File('foo.h5', 'r') as h_file:
),从中读取一个单独的块(chunk = h_file['label'][i : i + chunk_size]
)并返回该块。然后将聚集的块连接起来。然而,这失败了
OSError:无法读取数据(Fletcher32校验和检测到数据错误)。
这是因为我在多个进程中打开了相同的文件(如here建议的那样)?
所以我的最后一个问题是:如何更快地将.h5
文件的内容读入主内存?再次:»浪费«RAM有利于节省时间是允许的。内容必须驻留在主存储器中,因此通过读取行或分数来避免问题不是一种选择。我知道我可以只存储未压缩的.h5
文件,但这只是我喜欢使用的最后一个选项,因为SSD上的空间很少。我更喜欢避风港,压缩文件和快速阅读(理想情况下通过更好地利用可用资源)。
元信息:我使用python 3.5.2和h5py 2.8.0。
编辑:在读取文件时,SSD的工作速度为72 MB / s,远远超过其最大值。 .h5
文件是使用h5py的create_dataset
方法和compression="lzf"
选项创建的。
编辑2:这是(简化)我用来读取(压缩)HDF5文件内容的代码:
def opener(filename, label): # regular version
with h5py.File(filename, 'r') as h_file:
data = g_file[label][:]
return data
def fast_opener(filename, label): # multiple processes version
with h5py.File(filename, 'r') as h_file:
length = len(h_file[label])
pool = Pool() # multiprocessing.Pool and not multiprocessing.dummy.Pool
args_iter = zip(
range(0, length, 1000),
repeat(filename),
repeat(label),
)
chunks = pool.starmap(_read_chunk_at, args_iter)
pool.close()
pool.join()
return np.concatenate(chunks)
def _read_chunk_at(index, filename, label):
with h5py.File(filename, 'r') as h_file:
data = h_file[label][index : index + 1000]
return data
如您所见,解压缩是通过h5py透明地完成的。
h5py
通过过滤器处理LZF文件的解压缩。在C中实现的过滤器的源代码是available on the h5py Github here。看看implementation of lzf_decompress
,它是导致你瓶颈的功能,你可以看到它没有并行化(不知道它是否可以并行化,我会把这个判断留给那些对LZF内部工作更熟悉的人)。
话虽如此,我担心没有办法只需要你的巨大压缩文件和多线程解压缩它。据我所知,您的选择是:
multiprocessing
可能有帮助,但您需要注意进程间共享内存)并在解压缩后将所有内容重新连接在一起。