2014-06-17 11 views
20

Próbowałem pracować z Cythonem i natknąłem się na następujący osobliwy scenariusz, w którym funkcja sumująca w tablicy zajmuje 3 razy więcej czasu niż średnia z tablicy.Cython sum v/s mean memory jump

Oto moje trzy funkcje

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 

Oto czasy uruchomić w 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 

nie jestem w stanie wyjaśnić skoku pamięci w prostym cython_sum. Czy to z powodu jakiegoś przydziału pamięci? Ponieważ są to losowe liczby od 0 do 1. Suma wynosi około 500K.

Ponieważ line_profiler nie działa z cythoniem, nie udało mi się profilować mojego kodu.

+3

Na marginesie nie używaj sumy jako nazwy zmiennej, to cienie metody sumy wbudowanej. –

+2

To zdecydowanie dziwne. Próbowałem zasadniczo, aby te dwie metody zawierały ten sam dokładny kod i zauważyłem znaczną różnicę, mimo że oba generowały coś, co wydaje się być tym samym kodem c. Próbowałem również zmienić kolejność definicji metod, a to nie zmienia niczego. Jednak jeśli zastąpię definicję bufora A w sygnaturze wywołania za pomocą wpisanego widoku pamięci (zamiast zrobić to w metodzie), to oba te same taktowania. – JoshAdel

+1

Użyłem podwójnego zamiast FLOAT_t, a suma zajęła 1,17 ms avg 1,16 ms. –

Odpowiedz