A Python nagy teljesítményéről, rugalmasságáról és könnyű kezelhetőségéről szerzett hírnevet. Ezek az erények vezettek ahhoz, hogy alkalmazások, munkafolyamatok és területek hatalmas és egyre szélesebb körében használják. A nyelv felépítése – értelmezett jellege, futásidejű dinamizmusa – azonban azt jelenti, hogy a Python mindig is nagyságrendekkel lassabb volt, mint az olyan gép-natív nyelvek, mint a C vagy a C++.
Az évek során a fejlesztők különféle megoldásokat találtak ki a Python sebességkorlátozásaira. Például meg lehetett írni a teljesítményigényes feladatokat C-ben, és Pythonba csomagolni; sok gépi tanulási könyvtár pontosan ezt teszi. Vagy használhatja a Cythont, egy olyan projektet, amely lehetővé teszi, hogy a Python kódot olyan futásidejű típusinformációkkal szórja meg, amelyek lehetővé teszik a C-re fordítást.
De a megoldások sosem ideálisak. Nem lenne nagyszerű, ha egy meglévő Python programot úgy, ahogy van, drámaian gyorsabban tudnánk futtatni? A PyPy pontosan ezt teszi lehetővé.
PyPy vs. CPython
A PyPyPy az alap Python-értelmező, a CPython helyettesítője. Míg a CPython a Pythont köztes bájtkóddá fordítja, amelyet aztán egy virtuális gép értelmez, addig a PyPy just-in-time (JIT) fordítást használ a Python kód gép-natív assembly nyelvre fordításához.
Az elvégzendő feladattól függően a teljesítménynövekedés drámai lehet. Átlagosan a PyPy körülbelül 7,6-szorosára gyorsítja a Pythont, néhány feladatot pedig 50-szeresére vagy még nagyobb mértékben gyorsít fel. A CPython-értelmező egyszerűen nem végez ugyanolyan típusú optimalizálásokat, mint a PyPy, és valószínűleg soha nem is fog, mivel ez nem tartozik a tervezési céljai közé.
A legjobb az egészben, hogy a fejlesztőnek alig vagy egyáltalán nem kell erőfeszítéseket tennie a PyPy által nyújtott előnyök kihasználásához. Egyszerűen cserélje ki a CPython-t PyPy-ra, és nagyrészt készen is van. Van néhány kivétel, amelyeket alább tárgyalunk, de a PyPy kimondott célja a meglévő, változatlan Python kód futtatása és automatikus sebességnövekedés biztosítása.
A PyPyPy jelenleg támogatja a Python 2 és Python 3-at is, a projekt különböző inkarnációi révén. Más szóval, a PyPy különböző verzióit kell letöltenie attól függően, hogy a Python melyik verzióját fogja futtatni. A PyPy Python 2-es ága már sokkal régebb óta létezik, de a Python 3-as változatot az utóbbi időben hozták rendbe. Jelenleg támogatja mind a Python 3.5-öt (gyártási minőség), mind a Python 3.6-ot (béta minőség).
A PyPy amellett, hogy támogatja az összes Python alapnyelvet, együttműködik a Python ökoszisztéma eszközeinek túlnyomó többségével, például a pip
csomagolási vagy a virtualenv
virtuális környezetekkel. A legtöbb Python csomagnak, még a C modulokat tartalmazóaknak is, úgy kell működnie, ahogy van, bár vannak korlátozások, amelyekre alább kitérünk.
Hogyan működik a PyPy
A PyPy olyan optimalizálási technikákat használ, amelyek más dinamikus nyelvek just-in-time fordítóiban is megtalálhatóak. Elemzi a futó Python programokat, hogy meghatározza az objektumok típusinformációit, ahogyan azok létrejönnek és felhasználásra kerülnek a programokban, majd ezeket a típusinformációkat használja útmutatóként a gyorsításhoz. Ha például egy Python függvény csak egy vagy két különböző objektumtípussal dolgozik, a PyPy olyan gépi kódot generál, amely ezeket a speciális eseteket kezeli.
A PyPy optimalizálásai automatikusan, futásidőben történnek, így általában nem kell a teljesítményét finomítani. Egy haladó felhasználó kísérletezhet a PyPy parancssori opcióival, hogy gyorsabb kódot generáljon speciális esetekben, de erre csak ritkán van szükség.
A PyPyPy eltér attól is, ahogyan a CPython kezel néhány belső függvényt, de igyekszik megőrizni a kompatibilis viselkedést. A PyPy például másképp kezeli a szemétgyűjtést, mint a CPython. Nem minden objektum kerül azonnal begyűjtésre, ha kikerül a hatóköréből, így a PyPy alatt futó Python program nagyobb memóriaigényt mutathat, mint a CPython alatt futó. De ettől még használhatjuk a Python magas szintű szemétgyűjtési vezérlőit, amelyeket a gc
modulon keresztül tárunk fel, mint például a gc.enable()
, gc.disable()
és gc.collect()
.
Ha a PyPy JIT viselkedéséről szeretnénk információt kapni futásidőben, a PyPy tartalmaz egy modult, a pypyjit
, amely számos JIT horgot tár fel a Python alkalmazásunk számára. Ha van egy függvényed vagy modulod, amely úgy tűnik, hogy rosszul teljesít a JIT-tel, a pypyjit
lehetővé teszi, hogy részletes statisztikákat kapj róla.
Egy másik PyPy-specifikus modul, a __pypy__
, más PyPy-specifikus funkciókat tár fel, így hasznos lehet olyan alkalmazások írásához, amelyek kihasználják ezeket a funkciókat. A Python futásidejű dinamizmusa miatt lehetséges olyan Python-alkalmazásokat építeni, amelyek akkor használják ezeket a funkciókat, amikor a PyPy jelen van, és figyelmen kívül hagyják őket, amikor nincs jelen.
PyPyPy korlátok
Milyen varázslatosnak is tűnik a PyPy, nem varázslatos. A PyPy-nek vannak bizonyos korlátai, amelyek csökkentik vagy ellehetetlenítik a hatékonyságát bizonyos típusú programok esetében. Sajnos a PyPy nem teljesen univerzális helyettesítője a CPython alapkiadású futásidőnek.
A PyPy tiszta Python-alkalmazásokkal működik a legjobban
A PyPy mindig is a “tiszta” Python-alkalmazásokkal – azaz a Pythonban és semmi másban írt alkalmazásokkal – működött a legjobban. A C könyvtárakkal interfészes Python-csomagok, mint például a NumPy, nem teljesítettek ilyen jól, mivel a PyPy emulálja a CPython natív bináris interfészeit.
A PyPy fejlesztői faragtak ezen a problémán, és kompatibilisebbé tették a PyPy-t a C kiterjesztésektől függő Python csomagok többségével. A Numpy például most már nagyon jól működik a PyPy-vel. De ha maximális kompatibilitást szeretne a C bővítményekkel, használja a CPython-t.
A PyPy a legjobban a hosszabb futású programokkal működik
A PyPy Python programok optimalizálásának egyik mellékhatása, hogy a hosszabb futású programok profitálnak leginkább az optimalizációiból. Minél hosszabb ideig fut a program, annál több futásidejű típusinformációt tud gyűjteni a PyPy, és annál több optimalizálást tud végrehajtani. Az egyszer használatos Python szkriptek nem profitálnak az ilyesmiből. Azoknak az alkalmazásoknak, amelyek profitálnak belőle, jellemzően olyan ciklusaik vannak, amelyek hosszú ideig futnak, vagy folyamatosan futnak a háttérben – például webes keretrendszerek.
A PyPyPy nem végez idő előtti fordítást
A PyPyPy fordít Python kódot, de ez nem egy fordítóprogram Python kódhoz. A PyPy optimalizálásainak módja és a Python eredendő dinamizmusa miatt nincs mód arra, hogy az így kapott JITt-elt kódot önálló bináris állományként kiadjuk és újra felhasználjuk. Minden programot minden egyes futtatáshoz le kell fordítani. Ha gyorsabb, önálló alkalmazásként futtatható kóddá akarod fordítani a Pythont, használd a Cython, a Numba vagy a jelenleg kísérleti stádiumban lévő Nuitka projektet.