2014-06-17 13 views
20

Ho cercato di lavorare con Cython e ho riscontrato il seguente scenario particolare in cui una funzione di somma su un array richiede 3 volte la quantità di tempo che impiega la media di un array.Cython sum v/s mean jump di memoria

Qui ci sono i miei tre funzioni

cpdef FLOAT_t cython_sum(cnp.ndarray[FLOAT_t, ndim=1] A): 
    cdef double [:] x = A 
    cdef double sum = 0 
    cdef unsigned int N = A.shape[0] 
    for i in xrange(N): 
    sum += x[i] 
    return sum 

cpdef FLOAT_t cython_avg(cnp.ndarray[FLOAT_t, ndim=1] A): 
    cdef double [:] x = A 
    cdef double sum = 0 
    cdef unsigned int N = A.shape[0] 
    for i in xrange(N): 
    sum += x[i] 
    return sum/N 


cpdef FLOAT_t cython_silly_avg(cnp.ndarray[FLOAT_t, ndim=1] A): 
    cdef unsigned int N = A.shape[0] 
    return cython_avg(A)*N 

Qui ci sono i tempi di esecuzione in ipython

In [7]: A = np.random.random(1000000) 


In [8]: %timeit np.sum(A) 
1000 loops, best of 3: 906 us per loop 

In [9]: %timeit np.mean(A) 
1000 loops, best of 3: 919 us per loop 

In [10]: %timeit cython_avg(A) 
1000 loops, best of 3: 896 us per loop 

In [11]: %timeit cython_sum(A) 
100 loops, best of 3: 2.72 ms per loop 

In [12]: %timeit cython_silly_avg(A) 
1000 loops, best of 3: 862 us per loop 

non sono in grado di spiegare il salto di memoria in modo semplice cython_sum. È a causa dell'allocazione di memoria? Poiché questi sono numeri casuali da 0 a 1. La somma è di circa 500K.

Poiché line_profiler non funziona con cython, non sono stato in grado di profilare il mio codice.

+3

Su una nota a margine non utilizzare la somma come nome di variabile, ma ombreggia il metodo della somma incorporata. –

+2

Questo è decisamente strano. Ho provato essenzialmente a fare in modo che i due metodi contengano lo stesso codice esatto, e noto una differenza apprezzabile, nonostante entrambi generino quello che sembra essere lo stesso codice c. Ho anche provato a cambiare l'ordine delle definizioni dei metodi, e questo non sembra cambiare nulla. Tuttavia, se sostituisco la definizione del protocollo del buffer di A nella firma della chiamata con un memoryview tipizzato (invece di farlo nel metodo), i due producono gli stessi tempi. – JoshAdel

+1

Ho usato il doppio invece di FLOAT_t e la somma ha impiegato 1,17 ms avg era 1,16 ms –

risposta

1

Sembra che i risultati di @ nbren12 siano la risposta definitiva: questi results cannot be reproduced.

L'evidenza (e la logica) indicano che entrambi i metodi hanno lo stesso runtime.