Python on ansainnut maineen tehokkaana, joustavana ja helppona käyttää. Nämä hyveet ovat johtaneet sen käyttöön valtavassa ja kasvavassa valikoimassa sovelluksia, työnkulkuja ja aloja. Mutta kielen rakenne – sen tulkattu luonne, sen suoritusajan dynaamisuus – tarkoittaa, että Python on aina ollut suuruusluokkaa hitaampi kuin C:n tai C++:n kaltaiset konenatiiviset kielet.
Kehittäjät ovat vuosien varrella keksineet erilaisia kiertoteitä Pythonin nopeusrajoituksille. Voit esimerkiksi kirjoittaa suorituskykyintensiivisiä tehtäviä C-kielellä ja kääriä ne Pythonilla; monet koneoppimiskirjastot tekevät juuri näin. Tai voisit käyttää Cythonia, projektia, jonka avulla voit ripotella Python-koodiin suoritusaikaista tyyppitietoa, jonka avulla se voidaan kääntää C:ksi.
Mutta kiertotiet eivät koskaan ole ihanteellisia. Eikö olisi hienoa, jos voisimme vain ottaa olemassa olevan Python-ohjelman sellaisenaan ja ajaa sen huomattavasti nopeammin? Juuri sen PyPy mahdollistaa.
PyPy vs. CPython
PyPy on drop-in korvaaja varastossa olevalle Python-tulkille, CPythonille. Siinä missä CPython kääntää Python-koodin välitietokoodiksi, jonka virtuaalikone tulkkaa, PyPy kääntää Python-koodin just-in-time (JIT) -käännöksen avulla koneen omaksi assembler-kieleksi.
Suoritettavasta tehtävästä riippuen suorituskykyhyöty voi olla dramaattinen. Keskimäärin PyPy nopeuttaa Pythonia noin 7,6-kertaisesti, ja jotkut tehtävät nopeutuvat 50-kertaisesti tai enemmän. CPython-tulkki ei yksinkertaisesti suorita samantyyppisiä optimointeja kuin PyPy, eikä luultavasti tule koskaan tekemäänkään, koska se ei kuulu sen suunnittelutavoitteisiin.
Parasta on se, että PyPyn tarjoamien hyötyjen vapauttaminen vaatii kehittäjältä vain vähän tai ei lainkaan vaivaa. Vaihda vain CPython PyPyyn, ja suurimmaksi osaksi olet valmis. On olemassa muutamia poikkeuksia, joita käsitellään jäljempänä, mutta PyPyn julkilausuttu tavoite on ajaa olemassa olevaa, muuttamatonta Python-koodia ja tarjota sille automaattinen nopeuslisäys.
PyPy tukee tällä hetkellä sekä Python 2:ta että Python 3:a, projektin eri inkarnaatioiden kautta. Toisin sanoen sinun on ladattava eri versiot PyPystä riippuen siitä, mitä Python-versiota käytät. PyPyn Python 2 -haara on ollut olemassa paljon kauemmin, mutta Python 3 -versiota on viime aikoina päivitetty. Se tukee tällä hetkellä sekä Python 3.5:tä (tuotantolaatu) että Python 3.6:ta (beta-laatu).
Kaiken Python-kielen ydinkielen tukemisen lisäksi PyPy toimii suurimman osan Python-ekosysteemiin kuuluvien työkalujen kanssa, kuten pip
pakkaamiseen tai virtualenv
virtuaaliympäristöihin. Useimpien Python-pakettien, jopa niiden, joissa on C-moduuleja, pitäisi toimia sellaisenaan, vaikka on rajoituksia, joita käsittelemme jäljempänä.
Miten PyPy toimii
PyPy käyttää optimointitekniikoita, jotka löytyvät muista dynaamisten kielten just-in-time-kääntäjistä. Se analysoi käynnissä olevia Python-ohjelmia määrittääkseen objektien tyyppitiedot, kun niitä luodaan ja käytetään ohjelmissa, ja käyttää sitten näitä tyyppitietoja ohjeena nopeuttaakseen asioita. Jos esimerkiksi Python-funktio toimii vain yhden tai kahden eri objektityypin kanssa, PyPy luo konekoodia käsittelemään näitä erityistapauksia.
PyPyn optimoinnit hoidetaan automaattisesti ajon aikana, joten sen suorituskykyä ei yleensä tarvitse säätää. Edistynyt käyttäjä saattaa kokeilla PyPyn komentorivin optioita nopeamman koodin generoimiseksi erikoistapauksia varten, mutta vain harvoin tämä on tarpeen.
PyPy poikkeaa myös tavasta, jolla CPython käsittelee joitakin sisäisiä funktioita, mutta pyrkii säilyttämään yhteensopivat käyttäytymismallit. PyPy käsittelee esimerkiksi roskienkeruuta eri tavalla kuin CPython. Kaikkia objekteja ei kerätä heti pois, kun ne poistuvat soveltamisalasta, joten Python-ohjelma, jota ajetaan PyPy-ohjelmalla, saattaa näyttää suuremman muistijalanjäljen kuin CPython-ohjelmalla ajettaessa. Mutta voit silti käyttää Pythonin korkean tason roskienkeräysohjauksia, jotka paljastuvat gc
-moduulin kautta, kuten gc.enable()
, gc.disable()
ja gc.collect()
.
Jos haluat tietoa PyPyn JIT-käyttäytymisestä ajonaikana, PyPy sisältää moduulin pypyjit
, joka paljastaa monia JIT-koukkuja Python-sovelluksellesi. Jos sinulla on funktio tai moduuli, joka näyttää toimivan huonosti JIT:n kanssa, pypyjit
:n avulla voit saada yksityiskohtaisia tilastoja siitä.
Toinen PyPy-kohtainen moduuli, __pypy__
, paljastaa muita PyPy:lle ominaisia ominaisuuksia, joten se voi olla hyödyllinen kirjoitettaessa sovelluksia, jotka hyödyntävät näitä ominaisuuksia. Pythonin ajonaikaisen dynaamisuuden vuoksi on mahdollista rakentaa Python-sovelluksia, jotka käyttävät näitä ominaisuuksia, kun PyPy on läsnä, ja jättävät ne huomiotta, kun PyPy ei ole läsnä.
PyPy:n rajoitukset
Niin maagiselta kuin PyPy saattaakin vaikuttaa, se ei ole taikuutta. PyPy:llä on tiettyjä rajoituksia, jotka vähentävät tai estävät sen tehokkuuden tietynlaisissa ohjelmissa. Valitettavasti PyPy ei ole täysin yleispätevä korvaaja alkuperäiselle CPython-ajoajalle.
PyPy toimii parhaiten puhtaiden Python-sovellusten kanssa
PyPy on aina toiminut parhaiten ”puhtaiden” Python-sovellusten kanssa – eli sovellusten, jotka on kirjoitettu Pythonilla eikä millään muulla. Python-paketit, joilla on rajapinta C-kirjastojen kanssa, kuten NumPy, eivät ole pärjänneet yhtä hyvin johtuen tavasta, jolla PyPy emuloi CPythonin natiiveja binääriliitäntöjä.
PyPyn kehittäjät ovat karsineet tätä ongelmaa ja tehneet PyPystä yhteensopivamman useimpien C-laajennuksista riippuvaisten Python-pakettien kanssa. Esimerkiksi Numpy toimii nyt erittäin hyvin PyPyn kanssa. Mutta jos haluat maksimaalisen yhteensopivuuden C-laajennusten kanssa, käytä CPythonia.
PyPy toimii parhaiten pidempään juoksevien ohjelmien kanssa
Yksi sivuvaikutuksista siinä, miten PyPy optimoi Python-ohjelmia, on se, että pidempään juoksevat ohjelmat hyötyvät eniten sen optimoinnista. Mitä pidempään ohjelmaa ajetaan, sitä enemmän ajoaikaista tyyppitietoa PyPy voi kerätä ja sitä enemmän optimointeja se voi tehdä. Kerralla tehdyt Python-skriptit eivät hyödy tällaisesta. Niissä sovelluksissa, jotka hyötyvät, on tyypillisesti silmukoita, joita ajetaan pitkiä aikoja tai jotka toimivat jatkuvasti taustalla – esimerkiksi web-kehykset.
PyPy ei tee ennakkokäännöstä
PyPy kääntää Python-koodia, mutta se ei ole kääntäjä Python-koodille. Koska PyPy suorittaa optimoinnit ja Pythonille ominainen dynaamisuus, ei ole mitään tapaa emittoida tuloksena syntyvää JITt-käännettyä koodia itsenäisenä binäärinä ja käyttää sitä uudelleen. Jokainen ohjelma on käännettävä jokaista ajoa varten. Jos haluat kääntää Pythonin nopeammaksi koodiksi, joka voidaan ajaa itsenäisenä sovelluksena, käytä Cythonia, Numbaa tai tällä hetkellä kokeellista Nuitka-projektia.