A bit of cython





We got our hands on Cythona, thanks to self-isolation. The problem is prosaic - how to accelerate in python with minimal loss of syntax. One approach is using Cython (a mixture of C and python).



The publication with a loud title haunted . But little can be learned from the content of the publication, since the formulas and the resulting table are incorrect. Let's try to complete the picture started by the authors of the post and dot the and.



* Tests were carried out on odroid xu4, ubuntu mate, python 2.7.17.

Cython is easy to install (pip install cython).



We will torture all the same Fibonacci numbers. Let's create files for performance gain tests. For python language (test.py):



def test(n):
   a, b = 0.0, 1.0
   for i in range(n):
      a, b = a + b, a
   print (a)


For cython language (test2.pyx):



def test2(int n):
   cdef int i
   cdef double a=0.0, b=1.0
   for i in range(n):
      a, b = a + b, a
   print (a)


The cython file requires pre-build. Let's create a setup.py for it with the following content:



from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize('test2.pyx'))


And collect:



python setup.py build_ext --inplace


Now let's take the file from the mentioned post with tests and fix it a bit by adding the ability to enter your own number at the start (tests.py):



import test
import test2
import time

number = input('enter number: ')

start = time.time()
test.test(number)
end =  time.time()

py_time = end - start
print("Python time = {}".format(py_time))

start = time.time()
test2.test(number)
end =  time.time()

cy_time = end - start
print("Cython time = {}".format(cy_time))
print("Speedup = {}".format(py_time / cy_time))


Let's see what happened:



python tests.py


Results:



For python 2.7:

enter number: 10
Python time = 1.62124633789e-05
Cython time = 4.05311584473e-06
Speedup = 4.0

enter number: 100
Python time = 3.40938568115e-05
Cython time = 5.00679016113e-06
Speedup = 6.80952380952

enter number: 1000
Python time = 0.000224113464355
Cython time = 1.19209289551e-05
Speedup = 18.8

enter number: 100000
Python time = 0.0200171470642
Cython time = 0.000855922698975
Speedup = 23.3866295265




For python 3:



enter number: 10
Python time = 7.653236389160156e-05
Cython time = 2.8133392333984375e-05
Speedup = 2.7203389830508473

enter number: 100
Python time = 8.678436279296875e-05
Cython time = 3.170967102050781e-05
Speedup = 2.736842105263158

enter number: 1000
Python time = 0.00031876564025878906
Cython time = 4.673004150390625e-05
Speedup = 6.821428571428571

enter number: 100000
Python time = 0.01643967628479004
Cython time = 0.0004260540008544922
Speedup = 38.5858981533296




* the test2.pyx module was "rebuilt" with the command:

python3 setup.py build_ext --inplace

** installed by cython:

pip3 install cython



You can do without building test2.pyx using setup.py, for this you just need to add the lines to the tests.py file :



import pyximport
pyximport.install()


Now test2.pyx will be built on the fly each time tests.py is run, and there will be fewer files in the folder.



How to start cython on windows.



Despite the fact that cython allows assembling files for both python3 and python2, it was not possible to get a ready-made recipe for python3 .

With python3 the build command works:

python setup.py build_ext -i --compiler=msvc


However, for its full-fledged work, you need to install part of the visual studio 2019 components. What exactly to install is indicated in the solution here .



Therefore, there are two working options that allow you to work (build a file) in windows with cython.



The first one uses python2.7 and the mingw compiler.

The procedure is as follows.

1.Install cython itself under python2.7:

py -2 -m pip install cython


2. Install the mingw compiler:

mingw

3. After installing the compiler and adding it to the PATH windows, the .pyx file can be compiled with the command:

python setup.py build_ext -i --compiler=mingw32


The second is using python3.x and the msvc compiler.



How to run cython in jupyter notebook.



Sometimes it is necessary to test the work of the code visually using jupyter. In order not to compile the code in cmd every time, you can use cython right in the jupyter cells.

To do this, import cython by executing in the jupyter cell:

%load_ext cython


And let's execute some code in the next cell:

%%cython -a
import numpy as np

cdef int max(int a, int b):
    return a if a > b else b

cdef int chebyshev(int x1, int y1, int x2, int y2):
    return max(abs(x1 - x2), abs(y1 - y2))

def c_benchmark():
    a = np.random.rand(1000, 2)
    b = np.random.rand(1000, 2)
    
    for x1, y1 in a:
        for x2, y2 in b:
            chebyshev(x1, x2, y1, y2)


If everything is successful, then the output will be like this:




All Articles