Bawiłem się z Cython w ramach przygotowań do innych prac. Wypróbowałem prosty przypadek testowy i zauważyłem coś dziwnego w sposobie, w jaki mój kod radzi sobie z większymi problemami. Stworzyłem prostą funkcję min/max, która oblicza min i maksimum tablicy 2D float32 i porównała ją do działania numpy.min(a), numpy.max(a)
. Dla tablicy 10000 elementów wydajność była podobna. Dla tablicy 1000000 elementów, cyton działał znacznie gorzej. Oto mój kod Cython:Cython vs numpy wydajność skalowania
import numpy
cimport cython
cimport numpy
DTYPE = numpy.float32
ctypedef numpy.float32_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
def minmax_float32(numpy.ndarray[DTYPE_t, ndim=2] arr):
cdef DTYPE_t min = arr[0, 0]
cdef DTYPE_t max = arr[0, 0]
cdef int row_max = arr.shape[0]
cdef int col_max = arr.shape[1]
cdef int x, y
for y in range(row_max):
for x in range(col_max):
if arr[y, x] < min:
min = arr[y, x]
if arr[y, x] > max:
max = arr[y, x]
return min, max
A oto mój prosty rozrządu wykonane w ipython:
a = numpy.random.random(10000).reshape((100, 100)).astype(numpy.float32)
%timeit -r3 -n50 (numpy.min(a), numpy.max(a))
# 50 loops, best of 3: 22.2 µs per loop
%timeit -r3 -n50 minmax_float32(a)
# 50 loops, best of 3: 23.8 µs per loop
a = numpy.random.random(1000000).reshape((1000, 1000)).astype(numpy.float32)
%timeit -r3 -n50 (numpy.min(a), numpy.max(a))
# 50 loops, best of 3: 307 µs per loop
%timeit -r3 -n50 minmax_float32(a)
# 50 loops, best of 3: 1.22 ms per loop
307/22.2
# 13.82882882882883
1220/23.8
# 51.26050420168067
Czy ktoś ma pomysły dlaczego tak Cython trwa znacznie dłużej dla większego wkładu? I to było po prostu coś, z czym grałem, ale jeśli masz jakieś wskazówki lub sztuczki, chciałbym je usłyszeć. Z góry dziękuję.
Edit: Pobiegłem te testy na macbook 10.10 z 8 GB pamięci. Skompilowałem cyton z gcc z macports z flagami wymienionymi w ich tutorialach -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing
.
Co się stanie, jeśli odwrócisz wewnętrzne i zewnętrzne pętle? – mtrw
Dobre pytanie, trwa do ~ 7 ms. Wszystko, co zrobiłem, to przełączenie dwóch linii 'for'. – daveydave400
Zgaduję, że kompilator stara się prawidłowo autovectorize - patrz [to] (https://groups.google.com/d/msg/cython-users/LfBH6M7gNTc/B19uFB5YbYYJ). –