使用cython和h5py快速读取hdf5文件

Reading hdf5 file quickly with cython and h5py

我正在尝试加速一个 python3 函数,该函数获取一些数据,这是一个索引数组,如果它们满足特定条件则保存它们。我试图通过使用 "cython -a script.py" 来加速它,但瓶颈似乎是 h5py I/O 切片数据集。

我对 cython 比较陌生,所以我想知道是否有任何方法可以加快速度,或者我只是受限于这里的 h5py I/O?

这是我要改进的功能:

import numpy as np
import h5py

cimport numpy as np
cimport cython
from libc.math cimport sqrt

DTYPE64 = np.int64
ctypedef np.int64_t DTYPE64_t
DTYPE32 = np.int32
ctypedef np.int32_t DTYPE32_t

@cython.boundscheck(False)
@cython.wraparound(False)
def tag_subhalo_branch(np.ndarray[DTYPE64_t] halos_z0_treeindxs,
                       np.ndarray[DTYPE64_t] tree_pindx,
                       np.ndarray[DTYPE32_t] tree_psnapnum,
                       np.ndarray[DTYPE64_t] tree_psnapid,
                       np.ndarray[DTYPE64_t] tree_hsnapid, hf,
                       int size):

    cdef int i
    cdef double radial, progen_x, progen_y, progen_z
    cdef double host_x, host_y, host_z, host_rvir
    cdef DTYPE64_t progen_indx, progen_haloid, host_id
    cdef DTYPE32_t progen_snap
    cdef int j = 0
    cdef int size_array = size
    cdef np.ndarray[DTYPE64_t] backsplash_ids = np.zeros(size_array,
                                                         dtype=DTYPE64)


    for i in range(0, size_array):
        progen_indx = tree_pindx[halos_z0_treeindxs[i]]
        if progen_indx != -1:
            progen_snap = tree_psnapnum[progen_indx]
            progen_haloid = tree_psnapid[progen_indx]

            while progen_indx != -1 and progen_snap != -1:
                # ** This is slow **
                grp = hf['Snapshots/snap_' + str('%03d' % progen_snap) + '/']
                host_id = grp['HaloCatalog'][(progen_haloid - 1), 2]
                # **

                if host_id != -1:
                    # ** This is slow **
                    progen_x = grp['HaloCatalog'][(progen_haloid - 1), 6]
                    host_x = grp['HaloCatalog'][(host_id - 1), 6]
                    progen_y = grp['HaloCatalog'][(progen_haloid - 1), 7]
                    host_y = grp['HaloCatalog'][(host_id - 1), 7]
                    progen_z = grp['HaloCatalog'][(progen_haloid - 1), 8]
                    host_z = grp['HaloCatalog'][(host_id - 1), 8]
                    # **
                    radial = 0
                    radial += (progen_x - host_x)**2
                    radial += (progen_y - host_y)**2
                    radial += (progen_z - host_z)**2
                    radial = sqrt(radial)

                    host_rvir = grp['HaloCatalog'][(host_id - 1), 24]
                    if radial <= host_rvir:
                        backsplash_ids[j] = tree_hsnapid[
                            halos_z0_treeindxs[i]]
                        j += 1
                        break

                # Find next progenitor information
                progen_indx = tree_pindx[progen_indx]
                progen_snap = tree_psnapnum[progen_indx]
                progen_haloid = tree_psnapid[progen_indx]
    return backsplash_ids

如此处所述:http://api.h5py.org/h5py 使用 cython 代码与 HDF5 c 代码交互。因此,您自己的 cython 代码可能能够直接访问它。但我怀疑这需要更多的研究。

您的代码正在使用 h5py 的 Python 接口,cythonizing 不会触及它。

cython 代码最适合用于低级操作,尤其是不能表示为数组操作的迭代操作。首先研究和试验 numpy 示例。您正潜入游泳池深处的 cython

您是否尝试过仅使用 Python 和 numpy 来改进该代码?乍一看,我看到了很多多余的 h5py 调用。

====================

您的 radial 计算访问 h5py 索引 6 次,而它可以通过 2 次访问。也许您这样写是希望 cython 可以更快地执行以下计算比 numpy?

data = grp['HaloCatalog']
progen = data[progen_haloid-1, 6:9]
host = data[host_id-1, 6:9]
radial = np.sqrt((progren-host)**2).sum(axis=1))

为什么不加载所有 data[progen_haloid-1,:]data[host_id-1,:]?甚至全部data?我必须检查 h5py 何时从直接使用文件中的数组切换到 numpy 数组。无论如何,内存中数组的数学运算将比文件读取快得多。