Cython

2020-03-23

Python wint aan populariteit en dat is niet vreemd. Het is een snel te leren taal, eenvoudig in gebruik en uitstekend toepasbaar voor data science en machine learning. Echter… Python is traag. Erg traag.

En dan is er C. Een spruitjeslucht steekt op bij het typen over deze taal. C is niet hip, C is niet eenvoudig, maar het is de ongeëvenaarde snelheidsduivel onder de programmeertalen.

Konden we maar het beste van twee werelden krijgen…

 


H E T  B E S T E  V A N  T W E E  W E R E L D E N

 

 

Cython is een Python variant die een brug slaat tussen razendsnelle machinecode en prettig te schrijven Python code. Het principe is eenvoudig: een Python-achtig taaltje wordt getranspileerd naar C om vervolgens gecompileerd te worden naar machinecode. Je hebt dus per script een source file (.pyx), een getranspileerde file (.c) en een gecompileerde file (.pyd). Deze laatste wordt daadwerkelijk gebruikt bij het uitvoeren.

De syntactische verschillen tussen Python en Cython zijn niet zo groot. Variabelen worden voorzien van een C-achtige type declaratie. Deze plaats je vóór een variabele (en niet erachter zoals een type hint). Daarnaast zijn er 3 manieren om functies te definieren. Dit kan doormiddel van het keyword “cpdef”. Dit betekent dat zowel Python als Cython scripts deze mogen aanroepen, in tegenstelling tot “cdef” en “def”. Deze laatste mogen enkel door respectievelijk Cython en Python scripts worden aangeroepen. Voor lijsten geef je vooraf de lengte op, zodat het geheugen – iets waar je in Python niet over nadenkt – bij voorbaat gealloceerd kan worden.

 

B E N C H M A R K S

 

 

Waar Cython tekort schiet in creativiteit voor logo’s en naamgeving, blinkt ze uit in de benchmarks. Ziehier, een eenvoudig script om priemgetallen te berekenen in Python (links) en Cython (rechts). Uitgevoerd op een i7 Windows laptopje. Onderstaande functies worden elk aangeroepen met n = 5e4, dat zijn een hoop priemgetallen.

 

def primes(n):
    result = [2]
    x = 2
    while len(result) < n:
        for i in result:
            if x % i == 0:
                break
        else:
            result.append(x)
        x += 1
    return result
cpdef primes(int n):
    cdef int result[50000]
    cdef int i
    cdef int x = 2
    cdef int found = 1
    result[0] = 2
 
    while found < n:
        for i in range(found):
            if x % result[i] == 0:
                break
        else:
            result[found] = x
            found += 1
        x += 1
    return result
 

 

De resultaten van de benchmarking liegen er niet om:

Python: 80.26094341278076 seconden
Cython: 3.4931583404541016 seconden

Cython is hier bijna 23 keer zo snel. Best heftig hè?

 

N O  F R E E  L U N C H

 

Elk voordeel heb z’n nadeel en Cython is daarin niet uitgezonderd. Laat ik een paar nadelen opsommen die ik heb ondervonden:

*  Het spul werkend krijgen
De tutorials weten het zo fraai te verkopen. Helaas is de realiteit dat wanneer je met Cython aan de slag wilt, je tegen weinigzeggende foutmeldingen aanloopt. Het vergt wat uitzoekwerk voordat je een eerste Cython compilatie hebt voltooid.

*  Platform specifiek
Cython moet worden gecompileerd (want C) en dat is platformspecifiek. Met andere woorden: je moet voor alle ondersteunde platformen apart (cross)compileren. Met plain Python hoeft dat natuurlijk niet.

*  Syntax
Nee, de taal is er niet mooier op geworden met die “cdefs” en harde types. Sommige zaken zijn ook iets complexer, zoals het loopen door een lijst.

 


C O N C L U S I E

 

 

Ben je op zoek naar een flinke performance boost van je Python app? Overweeg dan eens om een deel in Cython te schrijven. Neem de complexiteit van de setup, de syntax en de platformondersteuning wel mee in je overweging. Kijk ook zeker eens naar Numba, Numpy en PyPy als alternatieve turbo’s op je applicatie.

 

Succes en zoals altijd: happy coding!


Bekijk alle posts van Ramon