Cython is a subset of python language which allows you to write faster c code. Using cython one can write code with speed comparable to C using simplicity of Python. You write your code in a file with extension .pyx and compile it either one by one manually or using a setup.py file whose code is shared below.
I thought to check the speedup gained using cython so I wrote two files. First one was a pure python.py file while other one was a cython (cython.pyx file). The results I got were pretty amazing:
Contents of python.py file:-
def aman(t): print "Normal Python functions" sum = 0 for i in range(t): for j in range(t): sum = sum + i*j
Running this code in IPython with t = 5000 took almost 2.37 seconds to complete.
Contents of cython.pyx file :-
def pyfun(t): print "Normal Python functions" sum = 0 for i in range(t): for j in range(t): sum = sum + i*j return sum def m_fun(int t): print "Python function with Static Typing" cdef int sum = 0, i, j for i in range(t): for j in range(t): sum = sum + i*j return sum cdef fun(int t): print "Cython function" cdef: int sum =0 int i = 0 int j = 0 for i in range(t): for j in range(t): sum = sum + i*j return sum def cfun(a): return _aman(a) cpdef int cpfun(int t): print "Cpdef function c type:" cdef: int sum =0 int i = 0 int j = 0 for i in range(t): for j in range(t): sum = sum + i*j return sum cpdef cppfun(t): sum = 0 print "Cpdef function python:" for i in range(t): for j in range(t): sum = sum + i*j return sum
The running time of these functions were quite interesting:-
1st:- pyfun():- Same python code copied as it is in cython:- Took 1.72 seconds.
2nd:- m_fun():- The python code with static types defined. Took 0.0222 seconds
3rd:- cfun():- The cdef fun with a python wrapper function:- Took 0.02279 seconds
4th:- cpfun():- Pure c code just defined as cpdef. Took 1.7299 seconds
5th:- cppfun():- The pyton code written using static pyhon declarations everyehre. Took almot 0.021 seconds to run.
This table shows the correct time taken by different cython functions :
No | Versions | Time taken | Speedup |
1 | Pure Python in .py file | 2.37 | 1 |
2 | Pure Python in .pyx file | 1.72 | 1.377906977 |
3 | python def function with static variable declarations | 0.0222 | 106.7567568 |
4 | cdef function | 0.019 | 124.7368421 |
5 | cpdef function without static declaration | 1.7299 | 1.370021389 |
6 | cpdef function with static declaration | 0.02099 | 81.94378275 |
P.S. The content of setup.py file are:-
from distutils.core import setup, Extension import numpy from Cython.Distutils import build_ext setup( cmdclass={'build_ext': build_ext}, ext_modules=[Extension("aman", sources=["aman.pyx"], include_dirs=[numpy.get_include()])])
The command required to automatically convert .pyx file to .so extension is:
>>> python setup.py build_ext –inplace
For time calculation in IPython the following commands can be used:-
>>> import timeit
>>> a = timeit.Timer(“python.aman(5000)”, “import python”)
>>>a = a.timeit(num) #num defines how many times you want to run the loop.
>>> print a
</Keep Coding>
Yes, that kind of nested loop is ideal for translating to Cython. A factor of ~100 can be gained in such cases.
The IPython magic command “%timeit“ is an easier way to do these timings.
The indentation in your code in this post is off by the way – no indents in the Python part and 8-space indents for Cython (should be 4 spaces everywhere, says PEP8).
Thanks Ralf for the suggestions. I will keep them in mind for future.
Also, in-place addition (+=) would be cleaner here.
0 Pingbacks