2016-10-07 6 views
0

Ich versuche, eine Python3-Funktion zu beschleunigen, die einige Daten, die ein Array von Indizes ist, und speichert sie, wenn sie ein bestimmtes Kriterium erfüllen. Ich habe versucht, es mit "Cython -a script.py" zu beschleunigen, aber der Flaschenhals scheint die h5py I/O Slicing Datasets zu sein.HdF5-Datei schnell mit Cython und H5py lesen

Ich bin relativ neu zu Cython, also fragte ich mich, ob es sowieso gibt, um dies zu beschleunigen, oder bin ich nur begrenzt durch die h5py I/O hier?

Hier ist die Funktion, die ich zu verbessern bin versucht:

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 
+0

'Cython' verbessert die Geschwindigkeit, wenn es die Aktion in' c' ausführen kann. Es kann auch eine "numpy" Indizierung mit seinen eigenen 'Memoryviews' durchführen. Aber es kann die 'h5py'-Indexierung nicht berühren. Dazu muss es 'h5py'-Funktionen aufrufen. "Cython" eignet sich am besten für innere Schleifen, die nicht als Array-Operationen ausgedrückt werden können. – hpaulj

Antwort

1

Wie hier beschrieben: http://api.h5py.org/, h5py verwendet cython Code mit dem HDF5c Code zu verbinden. So könnte Ihr eigener cython Code direkt darauf zugreifen können. Aber ich vermute, das wird viel mehr Studien erfordern.

Ihr Code verwendet die Python-Schnittstelle zu h5py, und cythonizing wird das nicht berühren.

cython Code wird am besten für Low-Level-Aktionen verwendet, insbesondere für iterative Dinge, die nicht als Array-Operationen ausgedrückt werden können. Studieren und experimentieren Sie zuerst mit den numpy Beispielen. Sie tauchen am tiefen Ende des Pools in cython ein.

Haben Sie versucht, diesen Code nur mit Python und numpy zu verbessern? Auf den ersten Blick sehe ich viele redundante h5py Anrufe.

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

Ihre radial Berechnung der h5py Indizierung 6 Mal zugreift, wenn es mit 2 erhalten, indem könnte Vielleicht schrieb man es, dass Weg in der Hoffnung, dass cython würde die folgende Berechnung schneller als numpy vorformulieren?

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)) 

Warum laden nicht alle data[progen_haloid-1,:] und data[host_id-1,:]? Sogar alle data? Ich müsste überprüfen, wenn h5py wechselt von der Arbeit direkt mit den Arrays in der Datei und wenn sie numpy Arrays werden. In jedem Fall ist die Berechnung von Arrays im Speicher viel schneller als das Lesen von Dateien.

+0

Danke Ich habe vorher mit Numpy experimentiert, aber ich hatte nicht gedacht, die Eingabeaufrufe mit dieser Technik zu reduzieren. Es ist jedoch immer noch ein wenig langsam, vielleicht ist es das Beste, etwas MPI-Formalismus zu benutzen, um die Aufgaben zu trennen? –