2016-06-30 16 views
4

Ich schreibe eine ziemlich große Simulation in Python und hoffte, etwas zusätzliche Leistung von Cython zu bekommen. Für den folgenden Code scheint ich jedoch nicht allzu viel zu bekommen, obwohl er eine ziemlich große Schleife enthält. Etwa 100.000 Iterationen.Cython Optimierung

Habe ich einige Anfänger Fehler gemacht oder ist diese Loop-Größe einfach zu klein, um einen großen Effekt zu haben? (In meinen Tests war der Cython-Code nur etwa 2 mal schneller).

import numpy as np; 
cimport numpy as np; 
import math 

ctypedef np.complex64_t cpl_t 
cpl = np.complex64 

def example(double a, np.ndarray[cpl_t,ndim=2] A): 

    cdef int N = 100 

    cdef np.ndarray[cpl_t,ndim=3] B = np.zeros((3,N,N),dtype = cpl) 

    cdef Py_ssize_t n, m; 
    for n in range(N): 
     for m in range(N): 

      if np.sqrt(A[0,n]) > 1: 
       B[0,n,m] = A[0,n] + 1j * A[0,m] 

    return B; 
+6

Sie machen einen 'np.sqrt' Aufruf innerhalb der Schleife. Das sieht nach einem Leistungsproblem aus. Warum ist es überhaupt in der Schleife? 'a' ändert sich nie. Warum nicht einfach 'wenn a <= 1: B vor der Schleife zurückgeben? – user2357112

+0

@GWW: Das sieht für mich die erste Reihe aus. – user2357112

+0

@ user2357112 Danke, das ist eigentlich etwas, das ich übersehen habe, ich kann das verschieben. Tatsächlich, sind mathematische Operationen wie np.sqrt() oder np.exp() etwas, das ich in Cython vermeiden sollte? – physicsGuy

Antwort

7

Sie sollten Compiler-Direktiven verwenden. Ich schrieb Ihre Funktion in Python

import numpy as np 

def example_python(a, A): 
    N = 100 
    B = np.zeros((3,N,N),dtype = np.complex) 
    aux = np.sqrt(A[0]) 
    for n in range(N): 
     if aux[n] > 1: 
      for m in range(N): 
       B[0,n,m] = A[0,n] + 1j * A[0,m] 
return B 

und in Cython

import cython 
import numpy as np 
cimport numpy as np 

ctypedef np.complex64_t cpl_t 
cpl = np.complex64 

@cython.boundscheck(False) # compiler directive 
@cython.wraparound(False) # compiler directive 
def example_cython(double a, np.ndarray[cpl_t,ndim=2] A): 

    cdef int N = 100 
    cdef np.ndarray[cpl_t,ndim=3] B = np.zeros((3,N,N),dtype = cpl) 
    cdef np.ndarray[float, ndim=1] aux 
    cdef Py_ssize_t n, m 
    aux = np.sqrt(A[0,:]).real 
    for n in range(N): 
     if aux[n] > 1.: 
      for m in range(N): 
       B[0,n,m] = A[0,n] + 1j * A[0,m] 
    return B 

ich beide Funktionen vergleichen (Sie können über Compiler-Direktiven here lernen)

c = np.array(np.random.rand(100,100)+1.5+1j*np.random.rand(100,100), dtype=np.complex64) 

%timeit example_python(100, c) 
10 loops, best of 3: 61.8 ms per loop 

%timeit example_cython(100, c) 
10000 loops, best of 3: 134 µs per loop 

Cython ist ~ 450-mal schneller als Python in diesem Fall.

+0

Vielen Dank, das war genau das, wonach ich suchte! Ich wusste noch nichts über Compiler-Richtlinien. – physicsGuy