pytables的写速度比h5py快得多。为什么?

D. *_*and 6 python pytables h5py

我注意到,如果我使用h5py库而不是pytables库,则编写.h5文件的时间会更长。是什么原因?当阵列的形状以前已知时,也是如此。此外,我使用相同的块大小,没有压缩过滤器。

以下脚本:

import h5py
import tables
import numpy as np
from time import time

dim1, dim2 = 64, 1527416

# append columns
print("PYTABLES: append columns")
print("=" * 32)
f = tables.open_file("/tmp/test.h5", "w")
a = f.create_earray(f.root, "time_data", tables.Float32Atom(), shape=(0, dim1))
t1 = time()
zeros = np.zeros((1, dim1), dtype="float32")
for i in range(dim2):
    a.append(zeros)
tcre = round(time() - t1, 3)
thcre = round(dim1 * dim2 * 4 / (tcre * 1024 * 1024), 1)
print("Time to append %d columns: %s sec (%s MB/s)" % (i+1, tcre, thcre))
print("=" * 32)
chunkshape = a.chunkshape
f.close()

print("H5PY: append columns")
print("=" * 32)
f = h5py.File(name="/tmp/test.h5",mode='w')
a = f.create_dataset(name='time_data',shape=(0, dim1),
                     maxshape=(None,dim1),dtype='f',chunks=chunkshape)
t1 = time()
zeros = np.zeros((1, dim1), dtype="float32")
samplesWritten = 0
for i in range(dim2):
    a.resize((samplesWritten+1, dim1))
    a[samplesWritten:(samplesWritten+1),:] = zeros
    samplesWritten += 1
tcre = round(time() - t1, 3)
thcre = round(dim1 * dim2 * 4 / (tcre * 1024 * 1024), 1)
print("Time to append %d columns: %s sec (%s MB/s)" % (i+1, tcre, thcre))
print("=" * 32)
f.close()
Run Code Online (Sandbox Code Playgroud)

在我的计算机上返回:

PYTABLES: append columns
================================
Time to append 1527416 columns: 22.679 sec (16.4 MB/s)
================================
H5PY: append columns
================================
Time to append 1527416 columns: 158.894 sec (2.3 MB/s)
================================
Run Code Online (Sandbox Code Playgroud)

如果我在每个for循环之后刷新,例如:

for i in range(dim2):
    a.append(zeros)
    f.flush()
Run Code Online (Sandbox Code Playgroud)

我得到:

PYTABLES: append columns
================================
Time to append 1527416 columns: 67.481 sec (5.5 MB/s)
================================
H5PY: append columns
================================
Time to append 1527416 columns: 193.644 sec (1.9 MB/s)
================================
Run Code Online (Sandbox Code Playgroud)

kcw*_*w78 11

这是PyTablesh5py写入性能的有趣比较。通常我使用它们来读取 HDF5 文件(通常会读取一些大型数据集),所以没有注意到这种差异。我的想法与@max9111 一致:随着写入数据集的大小增加,写入操作的数量减少,性能应该会提高。为此,我重新编写了您的代码,以使用更少的循环编写 N 行数据。(代码在最后)。
结果令人惊讶(对我来说)。主要发现:
1. 写入所有数据的总时间是循环次数的线性函数(对于 PyTables 和 h5py)。
2. PyTables 和 h5py 之间的性能差异只是随着数据集 I/O 大小的增加而略有改善。
3. Pytables 一次写入 1 行(1,527,416 次写入)的速度提高了 5.4 倍,一次写入 88 行(17,357 次写入)的速度提高了 3.5 倍。

这是一个比较性能的图。
性能比较图 带有上表值的图表。
性能基准数据

另外,我注意到您的代码注释说“追加列”,但您正在扩展第一个维度(HDF5 表/数据集的行)。我重写了您的代码以测试扩展第二维的性能(向 HDF5 文件添加列),并且看到了非常相似的性能。

最初我认为 I/O 瓶颈是由于调整数据集的大小。因此,我重新编写了示例以初始调整数组大小以保存所有行。这并没有提高性能(并且显着降低了 h5py 的性能)。这是非常令人惊讶的。不知道该怎么做。

这是我的例子。它使用 3 个变量来确定数组的大小(添加数据时):

  • cdim:列数(固定)
  • row_loops: # 写循环
  • block_size:每次循环写入的数据块大小
  • row_loops*block_size = 写入的总行数

我还对加一而不是零进行了小改动(以验证数据是否已写入,并将其移至顶部(并移出计时循环)。

我的代码在这里:

import h5py
import tables
import numpy as np
from time import time

cdim, block_size, row_loops = 64, 4, 381854 
vals = np.ones((block_size, cdim), dtype="float32")

# append rows
print("PYTABLES: append rows: %d blocks with: %d rows" % (row_loops, block_size))
print("=" * 32)
f = tables.open_file("rowapp_test_tb.h5", "w")
a = f.create_earray(f.root, "time_data", atom=tables.Float32Atom(), shape=(0, cdim))
t1 = time()
for i in range(row_loops):
    a.append(vals)
tcre = round(time() - t1, 3)
thcre = round(cdim * block_size * row_loops * 4 / (tcre * 1024 * 1024), 1)
print("Time to append %d rows: %s sec (%s MB/s)" % (block_size * row_loops, tcre, thcre))
print("=" * 32)
chunkshape = a.chunkshape
f.close()

print("H5PY: append rows %d blocks with: %d rows" % (row_loops, block_size))
print("=" * 32)
f = h5py.File(name="rowapp_test_h5.h5",mode='w')
a = f.create_dataset(name='time_data',shape=(0, cdim),
                     maxshape=(block_size*row_loops,cdim),
                     dtype='f',chunks=chunkshape)
t1 = time()
samplesWritten = 0
for i in range(row_loops):
    a.resize(((i+1)*block_size, cdim))
    a[samplesWritten:samplesWritten+block_size] = vals
    samplesWritten += block_size
tcre = round(time() - t1, 3)
thcre = round(cdim * block_size * row_loops * 4 / (tcre * 1024 * 1024), 1)
print("Time to append %d rows: %s sec (%s MB/s)" % (block_size * row_loops, tcre, thcre))
print("=" * 32)
f.close()
Run Code Online (Sandbox Code Playgroud)