Bon chose promise, …
On va prendre un cas simple pour voir facilement les différences avec une problématique bien connue qui est fibonacci. On peut le retrouver facilement sur la toile à toutes les sauces.
On va prendre un cas très défavorable pour python, la fonction récursive, testée avec python 3.5
Avant on vérifiera que cython est bien installé, et que les dépendances le sont elles aussi.
fib.py
| def fib_py(n):
if n < 2:
return n
return fib_py(n-2) + fib_py(n-1)
|
En cython, fib_cython.pyx
| def fibb(int n):
return fib_in_c(n)
cdef int fib_in_c(int n):
if n < 2:
return n
return fib_in_c(n-2) + fib_in_c(n-1)
|
fibb est la fonction qui sera utilisé pour son retour et qui sera un objet python, très important !
setup.py
1
2
3
4
5
6
7
8
9
10
11
12 | from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [
Extension('fib_cython',
['fib_cython.pyx'])]
setup(
name = 'my cython fibonacci',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
|
Souvent plus simple que de se taper les longues lignes de compilation,
Un petit
| python3 setup.py build_ext --inplace
|
On nous ramène un fichier avec l'extension so (nommé fib_cython.so dans l'exemple), c'est la libC qu'on utilisera pour importer dans le fichier principal python
so pour Unix, dll ou pyd pour Windows concernant les extensions créées par le setup.
test.py
1
2
3
4
5
6
7
8
9
10
11
12
13 | from fib import fib_py
from fib_cython import fibb
from time import clock
times = [0, 0]
for ind, f in enumerate((fib_py, fibb)):
start = clock()
res = f(38)
times[ind] = clock()-start
print("temps pour la fonction {}: {}".format(f.__name__, times[ind]))
print("cython est {} fois plus rapide".format(times[0]/times[1]))
|
Nos tests, enfin…
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | fred1599@Fred:~/Bureau$ python3 test.py
temps pour la fonction fib_py: 21.966182
temps pour la fonction fibb: 0.25559200000000004
cython est 85.94236908823436 fois plus rapide
fred1599@Fred:~/Bureau$ python3 test.py
temps pour la fonction fib_py: 23.007478000000003
temps pour la fonction fibb: 0.24599800000000016
cython est 93.52709371620902 fois plus rapide
fred1599@Fred:~/Bureau$ python3 test.py
temps pour la fonction fib_py: 22.220582
temps pour la fonction fibb: 0.24598800000000054
cython est 90.33197554352225 fois plus rapide
|
On voit qu'on tourne aux alentours de 90x le temps imparti par python.
C'est le pire des cas, si on prend l'exemple d'une fonction itérative (tiens un exercice pour toi), tu te rendras compte que le ratio est moins important. En général on tourne entre 10 et 25x le temps python, mais avant cython, il faut:
- Vérifier que l'algorithme choisi est efficace
- Utiliser au maximum les modules résultant d'un binding C (split, strip, sum, …)
- Utiliser numpy avant cython si possible
- Utiliser cython en cas de détresse (temps par exemple ne respectant pas les objectifs)
Bonne continuation…