No s'ha de confondre amb CPython. |
Tipus | llenguatge de programació |
---|---|
Data de creació | 28 juliol 2007 |
Desenvolupador | Robert Bradshaw, Stefan Behnel, et al. |
Epònim | Python i C |
Darrera versió estable | 3.0.11-1 () |
Majors implementacions | Python |
Dialecte de | Python |
Llenguatge de programació | Python |
Influenciat per | Python |
Sistema operatiu | Linux, Unix-like, Microsoft Windows i macOS |
Codi font | Codi font |
Llicència | Apache License |
Etiqueta d'Stack Exchange | Etiqueta |
Pàgina web | cython.org |
Cython és un llenguatge de programació que actua com un compilador estàtic que serveix per a optimitzar tant el llenguatge de programació de Python com el llenguatge de programació estés de Cython (el qual està basat en Pyrex). Aquest permet escriure extensions de C per Python amb la mateixa dificultat amb la qual escriuríem en el propi Python.
És una extensió d'un llenguatge de programació que té com a propòsit ajudar a un compilador de Cython per transformar els codis que són de Python a un tipus de codis de C. El codi de C es genera un cop i es compila mitjançant els principals compiladors de C / C++ a CPython 2.6, 2.7 (2.4+ amb Cython 0.20.x), així com 3.3 i totes les posteriors versions d'aquest.[1]
El llenguatge de Cython és un superconjunt de Python el qual també permet crides de funcions de C, la declaració de variables tipus C i atributs de classes. Tot això fa que el compilador pugui generar codi de tipus C molt eficient a partir de codi de tipus Cython.
Regularment s'executen proves d'integració en totes les versions que són compatibles amb CPython i les últimes branques que es troben en desenvolupament per tal d'assegurar que el codi que ha estat generat sigui perfectament compatible i ben adaptat a cada versió.
El suport de PyPy és un treball que es troba en progrés i el qual es considera majoritàriament utilitzable des de Cython 0.17. Tot això fa que Cython sigui el llenguatge de programació ideal per a biblioteques externes de C, agregar CPython en aplicacions que ja existeixen i també per a mòduls ràpids de C que permeten accelerar l'execució d'un codi de Python.[2]
Cython t'atorga la possibilitat de realitzar les següents tasques (les quals ajunten funcions tant de Python com de C):
Cython és un derivat del llenguatge anomenat Pyrex i alhora suporta més funcions i optimitzacions d'aquesta. Cython fou bifurcat de Pyrex l'any 2007 pels desarrolladors del paquet d'àlgebra de computadors de Sage perquè estaven descontents amb les limitacions de Pyrex i no podien obtenir “patches” de l'encarregat de Pyrex, Greg Ewing, el qual va imaginar un abast molt més petit per a la seva eina que la que van tenir els desenvolupadors de Sage. Aleshores, aquests desenvolupadors de Sage, van bifurcar Pyrex com a SageX. Quan van descobrir que les persones descarregaven Sage només per poder obtenir SageX i els desenvolupadors de paquets (Stefan Behnel inclòs, el qual manté la XML biblioteca LXML) també seguien mantenint les agulles de Pyrex, SageX es va separar del projecte de Sage i es va fusionar amb cython-lxml per finalment convertir-se en Cython.[3]
Cython funciona produint un mòdul estàndard de Python. Tanmateix, el comportament difereix de Python estàndard en què el codi del mòdul, originalment escrit en Python, es tradueix en C. Mentre que el codi resultant de C és ràpid, fa moltes crides a l'intèrpret CPython i a les biblioteques estàndard de CPython per realitzar treballs reals. Aquestes crides van estalviar considerablement el temps de desenvolupament de Cython, però els mòduls depenen en gran manera de la biblioteca estàndard i de l'intèrpret de Python.
Tot i que la majoria del codi està basat en C, normalment es requereix un petit carregador de tests escrit en Python. Tot i això, aquest no és un problema important a causa de la presència de l'intèrpret de Python.
Cython té una interfície de funció externa per invocar rutines de C / C ++ i la capacitat de declarar el tipus estàtic de paràmetres i resultats de subrutina, variables locals i atributs de classe.
Un programa Cython que implementi el mateix algorisme que un programa Python corresponent pot consumir menys recursos informàtics com ara memòria bàsica i cicles de processament a causa de diferències entre els models d'execució CPython i Cython. Un programa de Python bàsic és carregat i executat per la màquina virtual CPython, de manera que tant el temps d'execució com el propi programa consumeixen recursos informàtics. Un programa de Cython es compila amb codi C, que es compila més al codi de màquina, de manera que la màquina virtual només s'utilitza breument quan es carrega el programa.[4][5]
Cython utilitza:[6]
El rendiment depèn tant del codi C generat per Cython com de la composició d'aquest codi.
Per programar en Cython seguim els passos següents:[7]
L'avantatge essencial d'aquest enfocament, és que al barrejar perfectament codi Python/C (és a dir, C usant <python.h>) és que el codi Python existent es pot ajustar a gairebé la velocitat de C amb només afegir uns quants tipus estàtics a les declaracions i fent algunes adaptacions en els bucles crítics -sense necessitat d'una interfície complicada o molt invasiva del codi. La velocitat de codificació i la llegibilitat del codi segueix sent comparable a la del codi Python.
A causa de reducció del consum general en les estructures de control (especialment els bucles), les optimitzacions optimistes i la inferència de tipus, el codi Python compilat amb Cython normalment s'executa més ràpid que en l'intèrpret CPython 2.6.x, encara que les millores absolutes depenen en gran manera el codi. Amb les declaracions de tipus estàtics, l'acceleració típica en càlculs numèrics/matricials és de 100x-1000x[8] En comparació a la típica optimització amb Psyco (Python JIT compiler) què és entre 4x-100x.[9][10]
Cython està escrit en Python, així que treballa en Windows, Linux, i MacOS X.
Per millorar l'eficiència del codi Cython sovint és útil definir les variables definint el seu tipus de forma estàtica. D'aquesta manera ajudarem a Cython a escapar de la natura dinàmica de Python i generar un codi en C molt més ràpid. Aquestes declaracions poden fer que el codi resulti menys entenedor de cara a l'usuari, i per tant no és recomanable fer-ne ús sense coneixement previ, pero si se'n fa un ús lògic de les seves eines s'arriba a resultats molt més ràpids.
La declaració estàtica del tipus de cada variable segueix la següent estructura:
cdef <type> <variable>
Cython permet la declaració de tots els tipus de variables disponibles en codi C.
Tipus | Declaració |
---|---|
int | cdef int n = 10
|
float | cdef float n = 255.0
|
complex | cdef float complex fc = 1+1j
|
struct | cdef struct Eduardo:
int age
float height
|
union | cdef union Food:
char *spam
float *eggs
|
class | cdef class Teacher:
cdef int age, height
def __init__(self, a, s):
self.age = a
self.subject = s
def describe(self):
print("Our teacher is", self.age,
"years old and teaches", self.subject)
|
list | cdef list llista = []
|
ctuple | cdef (int, double) tupla = (1, 2.0)
|
Cython converteix de manera automàtica i correcte el tipus de la variable en Python al tipus especificat a la assignació a la variable en C. Això també inclou el tipus d'enters arbitraris de la mida per defecte de Python, on els desbordaments de valors en la conversió a un tipus C provocaran un “PythonOverflowError” en temps d'execució. El codi generat en C podrà manipular correctament i de manera segura amb les mides de les variables assignades. D'aquesta manera podem definir les variables que hagin de representar nombre enters com a int, i el propi Cython s'encarregarà de dictaminar si es tracta d'un char, un int, un long, etc.
De tot el llistat de possibles tipologies de les variables allistades anteriorment les més típiques són dues: int i float. En C, i per tant en Cython, la mida de les variables de tipus int es determina en funció del valor que hagi de representar, i per tant el nombre bits necessaris. Tenim char (8 bits, 256 valors), int (32 bits, 2³² valors) i long (64 bits, 2⁶⁴ valors). Pel que respecta als floats, distingim entre float (32 bits) i double (64 bits). Les variables double tenen major precisió a l'hora de realitzar càlculs més precisos, pero aquests són computacional més cars.
Cython permet 3 maneres diferents de declarar funcions:[11]
#La funció suma_deu pren un nombre enter com a paràmetre i li suma deu unitats
#funció definida amb def
def suma_deu(nombre):
int resultat = 0
resultat = nombre + 10
return resultat
#Funció definida amb cdef
cdef int suma_deu(int nombre):
int resultat = 0
resultat = nombre + 10
return resultat
#Funció definida amb cpdef
cpdef suma_deu(int nombre):
int resultat = 0
resultat = nombre + 10
return resultat
A part de la conversió entre tipus de Python i C, un segon possible coll d'ampolla que empitjora el rendiment del codi són els accessos i assignaments a memòria. Per poder accedir a aquests elements fent servir codi C i per tant molt més ràpidament farem ús dels memoryview. D'aquesta manera estarem declarant el tipus de totes les variables dins l'array de forma estàtica.
Els memoryview són estructures de C amb un apuntador a un Numpy array i totes les dades necessàries per fer un accés segur i ràpid als elements d'aquest (dimensions, tipus de les variables, …). El que estem creant no és una còpia d'aquest array, sinó una forma més eficaç d'accedir als elements d'aquest.
Quan declarem un memoryview seguirem la següent sintaxi:
Declaració | Dimensions |
---|---|
cdef <type> [:] <variable> | 1D |
cdef <type> [:,:] <variable> | 2D |
cdef <type> [:,:,:] <variable> | 3D |
Per millorar-ne encara més l'eficiència, si sabem que els elements de l'array són contigus a memoria podem fer la següent declaració:
Declaració | Dimensions i eix |
---|---|
cdef <type> [::1] <variable> | 1D, contigu en fila |
cdef <type> [:,::1] <variable> | 2D, contigu en fila |
cdef <type> [::1,:] <variable> | 2D, contigu en columna |
Com els elements del Numpys arrays sempre es troben contigus a memòria, l'ús d'aquests en combinació amb la declaració contigua a memòria suposen una gran millora en el rendiment.
Cython permet l'ús de directives que indiquen al compilador com ha de compilar el codi. Podem assignar aquestes directives a nivell global o a nivell local per una funció.
Algunes de les directives que permet Cython són les següents:[12]
Directiva | Valors | Valors per defecte | Descripció |
---|---|---|---|
boundscheck | True/False | True | Si es defineix a False, Cython és lliure d'assumir que les operacions d'indexació del codi no faran que s'aixequi cap IndexErrors. |
wraparound | True/False | True | En les matrius de Python es poden indexar en relació amb el final. |
cdivision | True/False | False | Modificarà els quocients del programa per elevar un ZeroDivisionError quan el divisor es 0. |
profile | True/False | False | Modificarà els quocients del programa per elevar un ZeroDivisionError quan el divisor es 0. |
La principal utilitat de Cython és la seva capacitat de convertir codis Python a codis C compilables. La conversió i/o compilació d'un fitxer es pot fer de dues maneres diferents:[13]
· La comanda cython pren un fitxer .py o .pyx i el compila a un fitxer C/C++. Es recomanable utilitzar l'extensió setuptools que proporciona Cython. D'aquesta manera podem especificar opcions de compilació.
$ cython fitxer.pyx
· La comanda cythonize pren un fitxer .py o .pyx i el compila a un fitxer C/C++. Després compila aquest fitxer a un mòdul executable el qual es importable des de Python.
$ cythonize -3 -i fitxer.pyx
L'eina cythonize ofereix alguns flags per modificar el seu comportament i ajudar a la generació del codi.[14]
-a | Genera un codi html del codi Python proporcionat. En aquest trobem acolorides aquelles zones on no
s'hagi pogut fer la conversió a codi C. És una forma pràctica de veure com podem modificar el nostre codi per afavorir la seva conversió. |
-2 | Especifica la versió del codi Python com la versió 2 |
-3 | Especifica la versió del codi Python com la versió 3 |
-i | Genera la versió en C del codi Python, i automàticament compila aquest per generar el mòdul executable. |
-f | Genera la versió en C del codi Python, però no compila aquest. |
En cas de generar la versió en C i voler compilar aquest des del terminal podem fer-ho de la següent manera:
$ cythonize -3 -f -a fitxer.pyx
$ gcc -Ofast -shared -Wall -fPIC -I <path> -o fitxer.so
El resultat d'aquesta execució, al igual que la del cas bàsic $cythonize -3 -i -a fitxer.pyx, genera tres fitxers:
# Exemple 1
$ cp fitxer.py fitxer.pyx
$ cythonize -3 -i -a fitxer.pyx
# Exemple 2
$ cp fitxer.py fitxer.pyx
$ cythonize -3 -f fitxer.pyx
$ gcc -Ofast -I /usr/local/miniconda-3/include/python3.6m fitxer.c -shared -Wall -fPIC -o fitxer.so
#Calcul de la sequencia de fibonacci en cython
import cython
import numpy as np
cpdef Fibonacci_recursiu(int lim_iter): #Recursivament
if lim_iter == 0:
return 0
elif lim_iter == 1:
return 1
else:
return (Fibonacci_recursiu(lim_iter - 1) + Fibonacci_recursiu(lim_iter - 2))
cpdef Fibonacci_iteratiu(int lim_iter): #Utilitzant un vector
cdef int [::1] vect_res = np.zeros(lim_iter)
cdef int i
vect_res[1] = 1
for i in range(2,lim_iter):
vect_res[i] = vect_res[i-1] + vect_res[i - 2]
return vect_res[lim_iter - 1]
Cython és particularment popular entre els usuaris científics de Python, on té "la audiència perfecta" segons el creador de Python Guido van Rossum. Trobem Cython en:
El domini de Cython no es limita només a informàtica numèrica. Per exemple, el kit d'eines XX lxml s'escriu majoritàriament a Cython, i al igual que el seu predecessor Pyrex, Cython s'utilitza per proporcionar enllaços Python per a moltes biblioteques C i C ++ com la biblioteca de missatgeria ZeroMQ. Cython també es pot utilitzar per desenvolupar programes paral·lels per a màquines de processador multicentre; aquesta característica fa ús de la biblioteca OpenMP.