Cpython vs cython vs numpy Array Leistung

Ich mache einige Leistungstest auf einer Variante des Primzahlengenerators von http://docs.cython.org/src/tutorial/numpy.html . Die folgenden Leistungsmaße sind bei kmax = 1000

Pure Python-Implementierung, läuft in CPython: 0.15s

Pure Python-Implementierung, läuft in Cython: 0,07s

def primes(kmax): p = [] k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] != 0: i = i + 1 if i == k: p.append(n) k = k + 1 n = n + 1 return p 

Pure Python + Numpy Implementierung, läuft in CPython: 1,25s

 import numpy def primes(kmax): p = numpy.empty(kmax, dtype=int) k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] != 0: i = i + 1 if i == k: p[k] = n k = k + 1 n = n + 1 return p 

Cython-Implementierung mit int *: 0,003s

 from libc.stdlib cimport malloc, free def primes(int kmax): cdef int n, k, i cdef int *p = <int *>malloc(kmax * sizeof(int)) result = [] k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] != 0: i = i + 1 if i == k: p[k] = n k = k + 1 result.append(n) n = n + 1 free(p) return result 

Das oben ist großartig, sieht aber schrecklich aus, da es zwei Kopien der Daten enthält … also habe ich versucht, es zu reimplementieren:

Cython + Numpy: 1.01s

 import numpy as np cimport numpy as np cimport cython DTYPE = np.int ctypedef np.int_t DTYPE_t @cython.boundscheck(False) def primes(DTYPE_t kmax): cdef DTYPE_t n, k, i cdef np.ndarray p = np.empty(kmax, dtype=DTYPE) k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] != 0: i = i + 1 if i == k: p[k] = n k = k + 1 n = n + 1 return p 

Fragen:

  1. Warum ist die numpy Array so unglaublich langsamer als eine Python-Liste, wenn auf CPython laufen?
  2. Was habe ich in der Cython + Numpy-Implementierung falsch gemacht? Cython ist offensichtlich nicht behandeln die numpy Array als int [] wie es sollte.
  3. Wie gebe ich ein numpy Array auf ein int *? Die unten funktioniert nicht

     cdef numpy.nparray a = numpy.zeros(100, dtype=int) cdef int * p = <int *>a.data 

  • Cython mit Array von Zeigern
  • Eine vektorisierte, numpige Funktion zu verhalten, verhält sich wie ein ufunc
  • Cython: cimport und import numpy als (beide) np
  • Force NumPy ndarray, um das Eigentum an seinem Gedächtnis in Cython zu nehmen
  • Cython: unsigned int Indizes für numpy Arrays gibt unterschiedliche Ergebnisse
  • Cythonpufferdeklarationen für Objektmitglieder
  • Mit Cython, um eine c ++ - Vorlage zu wickeln, um jedes numpy Array zu akzeptieren
  • Übergeben von numpy Arrays in Cython zu einer C-Funktion, die dynamisch zugewiesene Arrays erfordert
  • 3 Solutions collect form web for “Cpython vs cython vs numpy Array Leistung”

     cdef DTYPE_t [:] p_view = p 

    Verwenden Sie diese anstelle von p in den Berechnungen. Reduziert die Laufzeit von 580 ms auf 2,8 ms für mich. Über die exakt gleiche Laufzeit wie die Implementierung mit * int. Und das ist ungefähr das max, das man von diesem erwarten kann.

     DTYPE = np.int ctypedef np.int_t DTYPE_t @cython.boundscheck(False) def primes(DTYPE_t kmax): cdef DTYPE_t n, k, i cdef np.ndarray p = np.empty(kmax, dtype=DTYPE) cdef DTYPE_t [:] p_view = p k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p_view[i] != 0: i = i + 1 if i == k: p_view[k] = n k = k + 1 n = n + 1 return p 

    Warum ist die numpy Array so unglaublich langsamer als eine Python-Liste, wenn auf CPython laufen?

    Weil du es nicht ganz eingegeben hast. Benutzen

     cdef np.ndarray[dtype=np.int, ndim=1] p = np.empty(kmax, dtype=DTYPE) 

    Wie gebe ich ein numpy Array auf ein int *?

    Durch die Verwendung von np.intc als dtype, nicht np.int (das ist ein C long ). Das ist

     cdef np.ndarray[dtype=int, ndim=1] p = np.empty(kmax, dtype=np.intc) 

    (Aber wirklich, verwenden Sie eine Memoryview, sie sind viel sauberer und die Cython-Leute wollen die NumPy-Array-Syntax auf lange Sicht loswerden.)

    Beste Syntax habe ich bisher gefunden:

     import numpy cimport numpy cimport cython @cython.boundscheck(False) @cython.wraparound(False) def primes(int kmax): cdef int n, k, i cdef numpy.ndarray[int] p = numpy.empty(kmax, dtype=numpy.int32) k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] != 0: i = i + 1 if i == k: p[k] = n k = k + 1 n = n + 1 return p 

    Beachten Sie, wo ich numpy.int32 anstelle von int verwendet habe. Alles auf der linken Seite eines cdef ist ein C-Typ (also int = int32 und float = float32), während alles auf der rechten Seite davon (oder außerhalb eines cdef) ein Python-Typ ist (int = int64 und float = float64 )

    Python ist die beste Programmiersprache der Welt.