Co to jest PyPy? Szybszy Python bez bólu

Python zyskał reputację potężnego, elastycznego i łatwego w obsłudze. Te zalety doprowadziły do ​​jego wykorzystania w ogromnej i rosnącej różnorodności aplikacji, przepływów pracy i dziedzin. Jednak konstrukcja języka - jego interpretowana natura, dynamika środowiska wykonawczego - oznacza, że ​​Python zawsze był o rząd wielkości wolniejszy niż języki natywne dla maszyn, takie jak C czy C ++.

Przez lata programiści wymyślali różne obejścia ograniczeń szybkości Pythona. Na przykład, możesz napisać zadania wymagające dużej wydajności w C i opakować je w Pythonie; wiele bibliotek uczenia maszynowego robi dokładnie to. Lub możesz użyć Cythona, projektu, który pozwala spryskać kod Pythona informacjami o typie środowiska wykonawczego, które pozwalają na skompilowanie go do C.

Ale obejścia nigdy nie są idealne. Czy nie byłoby wspaniale, gdybyśmy mogli po prostu wziąć istniejący program w języku Python w  takiej postaci , w jakiej jest , i uruchomić go znacznie szybciej? Dokładnie na to pozwala PyPy.

Powiązane wideo: Używanie środowiska wykonawczego PyPy dla języka Python

PyPy kontra CPython

PyPy jest zamiennikiem standardowego interpretera języka Python, CPython. Podczas gdy CPython kompiluje Python do pośredniego kodu bajtowego, który jest następnie interpretowany przez maszynę wirtualną, PyPy używa kompilacji just-in-time (JIT) do tłumaczenia kodu Pythona na język asemblera maszynowego.

W zależności od wykonywanego zadania wzrost wydajności może być dramatyczny. Średnio PyPy przyspiesza Python około 7,6 razy, a niektóre zadania przyspieszane są 50 razy lub więcej. Interpreter CPythona po prostu nie wykonuje takich samych optymalizacji jak PyPy i prawdopodobnie nigdy tego nie zrobi, ponieważ nie jest to jeden z jego celów projektowych.

Najlepsze jest to, że programista nie potrzebuje żadnego wysiłku, aby odblokować korzyści, które zapewnia PyPy. Po prostu zamień CPython na PyPy iw większości przypadków gotowe. Istnieje kilka wyjątków, omówionych poniżej, ale deklarowanym celem PyPy jest uruchomienie istniejącego, niezmodyfikowanego kodu Pythona i zapewnienie mu automatycznego przyspieszenia.

PyPy obecnie obsługuje zarówno Python 2, jak i Python 3, poprzez różne wcielenia projektu. Innymi słowy, musisz pobrać różne wersje PyPy w zależności od wersji Pythona, na której będziesz działać. Python 2 gałąź PyPy istnieje znacznie dłużej, ale wersja Python 3 została ostatnio przyspieszona. Obecnie obsługuje zarówno Python 3.5 (jakość produkcyjna), jak i Python 3.6 (jakość beta).

Oprócz obsługi całego podstawowego języka Python, PyPy współpracuje z większością narzędzi w ekosystemie Python, takich jak  pip tworzenie pakietów lub  virtualenv środowiska wirtualne. Większość pakietów Pythona, nawet te z modułami C, powinna działać tak jak jest, chociaż istnieją ograniczenia, które omówimy poniżej.

Jak działa PyPy

PyPy wykorzystuje techniki optymalizacji, które można znaleźć w innych kompilatorach just-in-time dla języków dynamicznych. Analizuje uruchomione programy w języku Python, aby określić informacje o typach obiektów, gdy są one tworzone i używane w programach, a następnie wykorzystuje te informacje jako wskazówki w celu przyspieszenia działania. Na przykład, jeśli funkcja Pythona działa tylko z jednym lub dwoma różnymi typami obiektów, PyPy generuje kod maszynowy do obsługi tych konkretnych przypadków.

Optymalizacje PyPy są obsługiwane automatycznie w czasie wykonywania, więc generalnie nie musisz modyfikować jego wydajności. Zaawansowany użytkownik może eksperymentować z opcjami wiersza poleceń PyPy, aby wygenerować szybszy kod dla specjalnych przypadków, ale rzadko jest to konieczne.

PyPy również odbiega od sposobu, w jaki CPython obsługuje niektóre funkcje wewnętrzne, ale stara się zachować zgodne zachowania. Na przykład PyPy obsługuje czyszczenie pamięci inaczej niż CPython. Nie wszystkie obiekty są zbierane natychmiast po wyjściu z zakresu, więc program w Pythonie działający pod PyPy może wykazywać większy ślad pamięci niż podczas uruchamiania w CPythonie. Ale nadal można używać formantów zbierania śmieci Pythona wysokopoziomowych odsłonięte przez gcmoduł, jak gc.enable(), gc.disable()i gc.collect().

Jeśli chcesz uzyskać informacje o zachowaniu JIT PyPy w czasie wykonywania, PyPy zawiera moduł pypyjit, który ujawnia wiele punktów zaczepienia JIT w twojej aplikacji Python. Jeśli masz funkcję lub moduł, który wydaje się działać słabo z JIT, pypyjitumożliwia uzyskanie szczegółowych statystyk na ten temat.

Kolejny moduł __pypy__specyficzny dla PyPy, udostępnia inne funkcje specyficzne dla PyPy, więc może być przydatny do pisania aplikacji, które wykorzystują te funkcje. Ze względu na dynamikę środowiska wykonawczego Pythona możliwe jest tworzenie aplikacji w języku Python, które używają tych funkcji, gdy PyPy jest obecny i ignoruje je, gdy ich nie ma.

Ograniczenia PyPy

Choć PyPy może się wydawać magiczne, to nie jest magia. PyPy ma pewne ograniczenia, które zmniejszają lub uniemożliwiają jego skuteczność w przypadku niektórych rodzajów programów. Niestety, PyPy nie jest całkowicie uniwersalnym zamiennikiem standardowego środowiska wykonawczego CPython.

PyPy działa najlepiej z aplikacjami w czystym języku Python

PyPy zawsze działał najlepiej z „czystymi” aplikacjami Pythona - tj. Aplikacjami napisanymi w Pythonie i niczym więcej. Pakiety Pythona, które współpracują z bibliotekami C, takimi jak NumPy, nie radziły sobie tak dobrze ze względu na sposób, w jaki PyPy emuluje natywne interfejsy binarne CPythona. 

Programiści PyPy odeszli od tego problemu i uczynili PyPy bardziej kompatybilnym z większością pakietów Pythona, które zależą od rozszerzeń C. Na przykład Numpy działa teraz bardzo dobrze z PyPy. Ale jeśli chcesz mieć maksymalną zgodność z rozszerzeniami C, użyj CPython.

PyPy działa najlepiej z programami działającymi dłużej

Jednym z efektów ubocznych sposobu, w jaki PyPy optymalizuje programy w języku Python, jest to, że dłużej działające programy odnoszą największe korzyści z optymalizacji. Im dłużej program działa, tym więcej informacji o typie w czasie wykonywania może zebrać PyPy i tym więcej może dokonać optymalizacji. Jednorazowe skrypty Pythona nie skorzystają na tego rodzaju rzeczach. Aplikacje, które przynoszą korzyści, zazwyczaj mają pętle, które działają przez długi czas lub działają nieprzerwanie w tle - na przykład struktury internetowe.

PyPy nie wykonuje kompilacji z wyprzedzeniem

PyPy  kompiluje  kod w Pythonie, ale nie jest  kompilatorem  kodu w Pythonie. Ze względu na sposób, w jaki PyPy przeprowadza swoje optymalizacje i nieodłączną dynamikę Pythona, nie ma sposobu, aby wyemitować wynikowy kod JITted jako samodzielny plik binarny i ponownie go użyć. Każdy program musi być skompilowany dla każdego uruchomienia. Jeśli chcesz skompilować Pythona w szybszy kod, który może działać jako samodzielna aplikacja, użyj Cython, Numba lub obecnie eksperymentalnego projektu Nuitka.