2017-06-21 1 views
0

J'utilise prange afin de modifier un tableau. J'essaie d'avoir aussi peu de lignes jaunes possible dans la page HTML généré par le compilateur cython avec:Cython Prange - traitant avec __Pyx_ErrFetchWithState/__Pyx_ErrRestoreWithState

cython function_prange.pyx -a 

Mais lors de l'extraction d'une partie d'un tableau pour le modifier, je l'ai toujours ce genre de code qui est généré :

{ 
    #ifdef WITH_THREAD 
    PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure(); 
    #endif 
    #ifdef _OPENMP 
    #pragma omp flush(__pyx_parallel_exc_type) 
    #endif /* _OPENMP */ 
    if (!__pyx_parallel_exc_type) { 
     __Pyx_ErrFetchWithState(&__pyx_parallel_exc_type, &__pyx_parallel_exc_value, &__pyx_parallel_exc_tb); 
     __pyx_parallel_filename = __pyx_filename; __pyx_parallel_lineno = __pyx_lineno; __pyx_parallel_clineno = __pyx_clineno; 
     __Pyx_GOTREF(__pyx_parallel_exc_type); 
    } 
    #ifdef WITH_THREAD 
    PyGILState_Release(__pyx_gilstate_save); 
    #endif 
} 

Est-il possible d'éviter ces __Pyx_ErrFetchWithState/__Pyx_ErrRestoreWithState? Est-ce que c'est vraiment important?

Voici le code que j'utilise:

Une première fonction en ajoutant un double à la diagonale d'une matrice contenue dans une matrice de taille dans une function_nogil.pyx

import cython 

@cython.boundscheck(False) # turn off bounds-checking for entire function 
@cython.wraparound(False) # turn off negative index wrapping for entire function 
cdef void add_diag(double [:,:,:] a, int a_len, int a_wid, double coeff) nogil: 
    cdef int x_max = a_len 

    cdef int x 
    for x in xrange(x_max): 
     a[0,x,x] = a[0,x,x] + coeff 

Son tête dans function_nogil.pxd

cdef void add_diag(double [:,:,:] a, int a_len, int a_wid, double coeff) nogil 

la fonction en utilisant prange dans function_prange.pyx

@cython.boundscheck(False) # turn off bounds-checking for entire function 
@cython.wraparound(False) # turn off negative index wrapping for entire function 
def prange_loop_idx(double [:,:,:] a, int a_dim1, int a_dim2, int a_dim3, double coeff,int num_threads): 

    cdef int i = 0 

    with nogil,parallel(num_threads=num_threads): 
     for i in prange(a_dim1): 
      add_diag(a[i:i+1:,],a_dim2,a_dim3,coeff) 

Répondre

1

Ce n'est pas aussi mauvais que ça en al'air. Lorsque vous regardez le code C complet, vous verrez qu'il s'agit juste d'un bit de code de gestion d'erreur et qu'il ne sera exécuté qu'en sautant dessus avec goto suite à une condition d'erreur.

(La condition d'erreur est qu'elle vérifie que la tranche de mémoire est construite correctement - je pense que c'est une conséquence de l'utilisation d'une tranche plutôt que d'un seul index.

Donc, vous avez un peu de contrôle d'erreur supplémentaire qui est probablement pas strictement nécessaire, mais je pense serait sage de laisser seul (sur mon PC, il est cette ligne):

if (unlikely(__pyx_memoryview_slice_memviewslice(
    &__pyx_t_4, 
    __pyx_v_a.shape[0], __pyx_v_a.strides[0], __pyx_v_a.suboffsets[0], 
    0, 
    0, 
    &__pyx_t_5, 
    __pyx_v_i, 
    (__pyx_v_i + 1), 
    0, 
    1, 
    1, 
    0, 
    1) < 0)) 
{ 
    __PYX_ERR(0, 21, __pyx_L12_error) 
} 

mais le code réel vous vous inquiétez pas n'est pas appelé en fonctionnement normal, donc n'a presque aucun coût et vous pouvez ignorer.


Je pense que le code généré par parallel et prange est probablement suffisamment complexe que les fichiers HTML générés ne sont pas 100% utile à vous montrer les bits corrects, et c'est pourquoi vous le voir lié à celui ligne, mais vous ne voyez pas le code de vérification d'erreur que j'ai montré ci-dessus.