If we have a code on pure Python usually we can speed it up with some tiny changes using Cython.
In its core Cython is an intermediate between Python and C/C++. It allows you to write your Python code with minor changes and then translate it into C code.
As usual im referencing to official Cython documentation with all details.
The first thing we will do we will write our functions.
Lets use number calculations from other atricle in this blog.
We will start with recursive calculation.
# stern_python.py
def stern_n(n):
if n < 2:
return n
elif n % 2 == 0:
return stern_n(n/2)
else:
return stern_n((n - 1)/2) + stern_n((n + 1)/2)
def run_stern(n):
stern_array = list()
for i in range(n):
stern_array.append(int(stern_n(i)))
return stern_array
import stern_python as python_s
Our Cython equivalent of the same functions look very similar. For that we will create new file.
# stern_cython.pyx
cpdef int stern_n(int n):
if n < 2:
return n
elif n % 2 == 0:
return stern_n(n/2)
else:
return stern_n((n - 1)/2) + stern_n((n + 1)/2)
cpdef run_stern(int n):
stern_array = list()
for i in range(n):
stern_array.append(stern_n(i))
return stern_array
Next we will take list manupulation function with lazy calculation.
# hofsconwc_python.py
def hofsconwc(i):
hf = []
for n in range(i):
if n <= 2:
hf.append(1)
else:
hf.append(hf[hf[n-1]] + hf[n - hf[n-2]-1])
return hf
import hofsconwc_python as python_h
and our Cython variant.
# hofsconwc_python.pyx
cpdef hofsconwc(int i):
hf = []
for n in range(i):
if n <= 2:
hf.append(1)
else:
hf.append(hf[hf[n-1]] + hf[n - hf[n-2]-1])
return hf
Next we will create setup.py file which will compile the Cython into C code.
We will use *.pyx as filename because we wanna try multiple files compilation.
# setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(name='Testing calculation',
ext_modules=cythonize('*.pyx'),
requires=['Cython'], )
!ls -ll
All we need to do is just perform
!python setup.py build_ext --inplace
!ls -ll
It works! Now we can import Cython functions.
import stern_cython as cython_s
import hofsconwc_cython as cython_h
So we are ready to test our calculations with some magic functions.
%timeit _ = python_s.run_stern(10000)
%timeit _ = cython_s.run_stern(10000)
Yes we have x100 time speed up with just type definition and precompiling our functions.
But what if we will try more real functions like hofsconwc without useless recursion.
%timeit _ = python_h.hofsconwc(10000)
%timeit _ = cython_h.hofsconwc(10000)
Yes so easy we get x2 speed up for our calculations.
Comments
comments powered by Disqus