Cython: accélération de code Python supérieure à 30x

Python est un langage que de nombreux programmeurs adorent. Cette langue est incroyablement facile Ă  utiliser. Le fait est que le code Ă©crit en Python est intuitif et d'une bonne lisibilitĂ©. Cependant, dans les conversations sur Python, on peut souvent entendre la mĂȘme plainte Ă  propos de ce langage. Surtout quand les experts C parlent de Python. VoilĂ  comment ça sonne: "Python est lent." Et ceux qui le disent ne pĂšchent pas contre la vĂ©ritĂ©.

Comparé à de nombreux autres langages de programmation, Python est, en effet, lent. Voici les résultats des tests qui comparent les performances de différents langages de programmation pour résoudre divers problÚmes.



Il existe plusieurs façons d'accĂ©lĂ©rer les programmes Python. Par exemple, vous pouvez utiliser des bibliothĂšques conçues pour utiliser plusieurs cƓurs de processeur. Ceux qui travaillent avec Numpy, Pandas ou Scikit-Learn peuvent ĂȘtre invitĂ©s Ă  jeter un Ɠil au progiciel Rapids , qui vous permet d'utiliser le GPU dans des calculs scientifiques.

Toutes ces techniques d'accĂ©lĂ©ration sont bonnes dans les cas oĂč les tĂąches pouvant ĂȘtre rĂ©solues Ă  l'aide de Python peuvent ĂȘtre parallĂ©lisĂ©es. Par exemple, ce sont des tĂąches de traitement prĂ©liminaire des donnĂ©es ou des opĂ©rations avec des matrices.

Mais que faire si votre code est purement Python? Que faire si vous avez une grande boucle for que vous devez absolument utiliser et dont l'exĂ©cution ne peut tout simplement pas ĂȘtre parallĂ©lisĂ©e du fait que les donnĂ©es qui y sont traitĂ©es doivent ĂȘtre traitĂ©es sĂ©quentiellement? Existe-t-il un moyen d'accĂ©lĂ©rer Python lui-mĂȘme?

La réponse à cette question est donnée par Cython - un projet à l'aide duquel vous pouvez accélérer considérablement le code écrit en Python.

Qu'est-ce que Cython?


Cython, à sa base, est une couche intermédiaire entre Python et C / C ++. Cython vous permet d'écrire du code Python ordinaire avec quelques modifications mineures, qui est ensuite directement traduit en code C.

La seule modification apportée au code Python consiste à ajouter des informations sur son type à chaque variable. Lors de l'écriture de code Python normal, vous pouvez déclarer une variable comme celle-ci:

 x = 0.5 

Lorsque vous utilisez Cython lors de la déclaration d'une variable, vous devez spécifier son type:

 cdef float x = 0.5 

Cette construction indique Ă  Cython que la variable est un nombre Ă  virgule flottante. Selon le mĂȘme principe, les variables sont dĂ©clarĂ©es en C. En utilisant Python ordinaire, les types de variables sont dĂ©finis dynamiquement. La dĂ©claration de type explicite utilisĂ©e en Cython est ce qui permet de convertir du code Python en code C. Le fait est qu'en C, une dĂ©claration explicite des types de variables est nĂ©cessaire.

L'installation de Cython est extrĂȘmement simple:

 pip install cython 

Types en Cython


Lors de l'utilisation de Cython, deux ensembles de types peuvent ĂȘtre distinguĂ©s. L'une concerne les variables, la seconde les fonctions.

Si nous parlons de variables, les types suivants sont Ă  notre disposition:

  • cdef int a, b, c
  • cdef char *s
  • cdef float x = 0.5 (nombre simple prĂ©cision)
  • cdef double x = 63.4 (nombre Ă  double prĂ©cision)
  • cdef list names
  • cdef dict goals_for_each_play
  • cdef object card_deck

Veuillez noter qu'ici, en fait, les types C / C ++ sont affichés!

Lorsque vous travaillez avec des fonctions, les types suivants sont disponibles:

  • def est une fonction Python rĂ©guliĂšre, appelĂ©e uniquement Ă  partir de Python.
  • cdef est une fonction Cython qui ne peut pas ĂȘtre appelĂ©e Ă  partir du code Python standard. Ces fonctions ne peuvent ĂȘtre appelĂ©es que dans le code Cython.
  • cpdef - Une fonction accessible Ă  la fois depuis C et Python.

Maintenant que nous avons compris les types de Python, nous allons prendre la vitesse du code Python.

Accélérer le code à l'aide de Cython


Commençons par créer un benchmark Python. Ce sera une boucle for dans laquelle la factorielle d'un nombre est calculée. Le code Python pur correspondant ressemblerait à ceci:

 def test(x):    y = 1    for i in range(1, x+1):        y *= i    return y 

L'Ă©quivalent cython de cette fonction est trĂšs similaire Ă  sa version originale. Le code correspondant doit ĂȘtre placĂ© dans un fichier avec l'extension .pyx . La seule modification Ă  apporter au code consiste Ă  ajouter des informations sur les types de variables et Ă  y fonctionner:

 cpdef int test(int x):    cdef int y = 1    cdef int i    for i in range(1, x+1):        y *= i    return y 

Notez que la fonction est cpdef mot clé cpdef . Cela vous permet d'appeler cette fonction depuis Python. De plus, le type est affecté à la variable i , qui joue le rÎle d'un compteur de boucle. N'oublions pas que nous devons taper toutes les variables déclarées dans la fonction. Cela permettra au compilateur C de savoir quels types utiliser.

Créez maintenant le setup.py , qui nous aidera à convertir le code Cython en code C:

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

Compilons:

 python setup.py build_ext --inplace 

Le code C est maintenant prĂȘt Ă  l'emploi.

Si vous regardez le dossier dans lequel se trouve le code Cython, vous y trouverez tous les fichiers nĂ©cessaires pour exĂ©cuter le code C, y compris le fichier run_cython.c . Si vous ĂȘtes intĂ©ressĂ©, ouvrez ce fichier et regardez quel code C gĂ©nĂ©rĂ© par Cython.

Vous ĂȘtes maintenant prĂȘt Ă  tester notre code C ultra-rapide. Vous trouverez ci-dessous le code utilisĂ© pour tester et comparer deux versions du programme.

 import run_python import run_cython import time number = 10 start = time.time() run_python.test(number) end = time.time() py_time = end - start print("Python time = {}".format(py_time)) start = time.time() run_cython.test(number) end = time.time() cy_time = end - start print("Cython time = {}".format(cy_time)) print("Speedup = {}".format(py_time / cy_time)) 

Ce code est trĂšs simple. Nous importons les fichiers nĂ©cessaires - tout comme les fichiers Python ordinaires sont importĂ©s, puis nous appelons les fonctions correspondantes, en procĂ©dant de la mĂȘme maniĂšre que si nous travaillions avec des fonctions Python rĂ©guliĂšres tout le temps.

Jetez un Ɠil au tableau suivant. Vous pouvez remarquer que la version Cython du programme est plus rapide que sa version Python dans tous les cas. Plus la tĂąche est grande, plus l'accĂ©lĂ©ration fournie par Cython est grande.
Numéro
Python Time Metric
Métrique de temps Cython
Score d'accélération
10
1.6689300537109375e-06
4.76837158203125e-07
3,5
100
3.337860107421875e-06
4.76837158203125e-07
7.0
1000
2.193450927734375e-05
9.5367431640625e-07
23,0
10 000
0.0002090930938720703
6.4373016357421875e-06
32.481
100 000
0,0021562576293945312
6.008148193359375e-05
35,89
1 000 000
0,02128767967224121
0,0005953311920166016
35,75
10 000 000
0,2148280143737793
0,00594782829284668
36.1187317112278

Résumé


L'utilisation de Cython peut accélérer considérablement presque tout code écrit en Python, sans faire d'effort particulier. Plus le programme comporte de boucles et plus il traite de données, meilleurs sont les résultats que vous pouvez attendre de Cython.

Chers lecteurs! Utilisez-vous Cython dans vos projets?

Source: https://habr.com/ru/post/fr462487/


All Articles