【发布时间】:2019-08-13 06:50:52
【问题描述】:
我有几个大的 HDF5 文件存储在 SSD 上(lzf 压缩文件大小为 10–15 GB,未压缩大小为 20–25 GB)。将此类文件中的内容读入 RAM 以进行进一步处理,每个文件大约需要 2 分钟。在此期间,仅使用一个内核(但达到 100%)。所以我猜解压部分在CPU上运行是瓶颈,而不是SSD的IO吞吐。
在我的程序开始时,它会将多个此类文件读入 RAM,这需要相当长的时间。 我喜欢通过利用更多内核和最终更多 RAM 来加速该过程,直到 SSD IO 吞吐量成为限制因素。我正在使用的机器有大量资源(20 个 CPU 内核 [+ 20 HT] 和 400 GB RAM),而且“浪费” RAM 没什么大不了的,只要节省时间是合理的。
我自己有两个想法:
1) 使用 python 的multiprocessing 模块将多个文件并行读入 RAM。这原则上可行,但由于在 multiprocessing 中使用了 Pickle(如 here 所述),我达到了 4 GB 的序列化限制:
OverflowError('无法序列化大于 4 GiB 的字节对象')。
2) 让多个进程(使用multiprocessing 模块中的Pool)打开同一个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透明完成的。
【问题讨论】:
-
如果您使用的是 Linux(假设),请查看
iotop。确保您的磁盘 IO 不会成为瓶颈。否则无论你创建多少进程都不会加快加载速度。 -
解压是怎么做的?在我看来,问题在于 LZF 解压缩运行单核,独立于您使用 HDF5 文件这一事实。
-
由于这是一个 IO 密集型工作负载,并且读取和(解)压缩可能发生在 C 代码中,请使用
threading.Threads(或multiprocessing.dummy.Pool,如果您喜欢multiprocessingAPI)。它不应该像 Python 线程那样受 GIL 的约束。 -
@user3389669 可以添加将文件加载到内存中的代码吗?你是显式解压还是由h5py处理?
-
我认为方法 2 应该可行。创建工作人员时是否有可能在父进程中打开文件?我discovered 说工作人员最终可能会共享文件句柄,这会导致奇怪的错误,因为他们都尝试使用相同的文件描述符进行查找和读取。
标签: python python-3.x hdf5 h5py