Cython is not much faster than Python for calculating the principal.

I am trying to follow the example given in the Continuum Analytics blog comparing Python, Cython, Numba for the amount calculated using the for loop. Unfortunately, I see that Cython is slower than Python!

Here is my Python function definition:

def python_sum(y): N = len(y) x = y[0] for i in xrange(1,N): x += y[i] return x 

And now my Cython function:

 def cython_sum(int[:] y): cdef int N = y.shape[0] cdef int x = y[0] cdef int i for i in xrange(1,N): x += y[i] return x 

Now I have a script that pulls out two functions and tests:

 import timeit import numpy as np import cython_sum import python_sum b = np.ones(10000) timer = timeit.Timer(stmt='python_sum.python_sum(b)', setup='from __main__ import python_sum, b') print "Python Sum (ms): %g" % (timer.timeit(1)*1000) timer = timeit.Timer(stmt='cython_sum.cython_sum(b)', setup='from __main__ import cython_sum, b') print "Cython (ms): %g" % (timer.timeit(1)*1000) 

And now my conclusion:

 Python Sum (ms): 9.44624 Cython (ms): 8.54868 

Based on the graphs in the blog post above, I was expecting a 100x - 1000x speed increase, and yet all I can see is that Cython is a little faster than vanilla Python.

Am I doing something wrong here? This seems like a pretty simple question with a simple function definition, and obviously, many people use Cython with great success, so it is clear that the error must lie with me. Can someone shed some light on this and tell me what I'm doing wrong? Thanks!

+6
source share
1 answer

I am not sure why you got this result. As the commentator said, your code, as it is, should not even work, since you will pass the float to a function that expects int s. Maybe you left the file cython_sum.py lying in the same directory?

I did the following. I created python_sum.py that contained your exact python_sum definition. Then I changed your Cython code a bit:

cython_sum.pyx

 def cython_sum(long[:] y): #changed `int` to `long` cdef int N = y.shape[0] cdef int x = y[0] cdef int i for i in xrange(1,N): x += y[i] return x 

I created an installation file to be able to create a Cython module:

setup.py

 from distutils.core import setup from Cython.Build import cythonize setup( name = 'Cython sum test', ext_modules = cythonize("cython_sum.pyx"), ) 

I built the module using python setup.py build_ext --inplace . Then I checked your test code with some changes:

test.py

 import timeit import numpy as np import cython_sum import python_sum # ** added dtype=np.int to create integers ** b = np.ones(10000, dtype=np.int) # ** changed .timeit(1) to .timeit(1000) for each one ** timer = timeit.Timer(stmt='python_sum.python_sum(b)', setup='from __main__ import python_sum, b') print "Python Sum (ms): %g" % (timer.timeit(1000)*1000) timer = timeit.Timer(stmt='cython_sum.cython_sum(b)', setup='from __main__ import cython_sum, b') print "Cython (ms): %g" % (timer.timeit(1000)*1000) 

And I got the following result:

 $ python test.py Python Sum (ms): 4111.74 Cython (ms): 7.06697 

Now it's a nice boost!


In addition, following the recommendations here , I was able to get an additional (small) speed:

cython_fast_sum.pyx

 import numpy as np cimport numpy as np DTYPE = np.int ctypedef np.int_t DTYPE_t def cython_sum(np.ndarray[DTYPE_t, ndim=1] y): cdef int N = y.shape[0] cdef int x = y[0] cdef int i for i in xrange(1,N): x += y[i] return x 

setup_fast.py

 from distutils.core import setup from Cython.Build import cythonize import numpy as np setup( name = 'Cython fast sum test', ext_modules = cythonize("cython_fast_sum.pyx"), include_dirs = [np.get_include()], ) 

test.py

 import timeit import numpy as np import cython_sum import cython_fast_sum b = np.ones(10000, dtype=np.int) # ** note 100000 runs, not 1000 ** timer = timeit.Timer(stmt='cython_sum.cython_sum(b)', setup='from __main__ import cython_sum, b') print "Cython naive (ms): %g" % (timer.timeit(100000)*1000) timer = timeit.Timer(stmt='cython_fast_sum.cython_sum(b)', setup='from __main__ import cython_fast_sum, b') print "Cython fast (ms): %g" % (timer.timeit(100000)*1000) 

Result:

 $ python test.py Cython naive (ms): 676.437 Cython fast (ms): 645.797 
+10
source

All Articles