PyPy - jak może pokonać CPython?

264

Z bloga Google Open Source :

PyPy to reimplementacja Pythona w Pythonie, wykorzystująca zaawansowane techniki w celu uzyskania lepszej wydajności niż CPython. Wiele lat ciężkiej pracy w końcu się opłaciło. Nasze wyniki prędkości często przekraczają CPython, od bycia nieco wolniejszym, do przyspieszeń do 2x w prawdziwym kodzie aplikacji, do przyspieszeń do 10x w małych testach porównawczych.

Jak to jest możliwe? Której implementacji Python użyto do implementacji PyPy? CPython ? A jakie są szanse, że PyPyPy lub PyPyPyPy pokonają swój wynik?

(Na powiązaną notatkę ... dlaczego ktoś miałby spróbować czegoś takiego?)

Agnel Kurian
źródło
43
Nitpick: PyPy to PyPyPy. Pomyśl o prefiksie Py- * jako operatorze projekcji.
u0b34a0f6ae
Dobrze. więc PyPy powinien być lepszy niż CPython? czy ma jakieś wady?
balki
10
PyPy jest doskonały w optymalizacji środowiska wykonawczego, ale jego różne wewnętrzne cechy sprawiają, że jest niekompatybilny z kilkoma popularnymi rozszerzeniami C.
Cees Timmerman,
4
Prawie wszystkim brakuje pytania, w jaki sposób teoretycznie możliwy jest wzrost prędkości. Ale zastanów się: Python potrafi wszystko, podobnie jak maszyna Turinga. W gcckońcu może zadzwonić . Możesz więc napisać kod Pythona, który działa na CPython, który interpretuje inny kod Pythona, tłumaczy go na C i wykonuje gcc, a następnie uruchamia skompilowany program. I może być szybszy, jeśli kod jest wywoływany wystarczająco często.
osa

Odpowiedzi:

155

Pytanie 1 Jak to jest możliwe?

Ręczne zarządzanie pamięcią (czyli to, co CPython robi z liczeniem) może być wolniejsze niż automatyczne zarządzanie w niektórych przypadkach.

Ograniczenia w implementacji interpretera CPython wykluczają pewne optymalizacje, które może wykonać PyPy (np. Drobnoziarniste zamki).

Jak wspomniał Marcelo, JIT. Będąc w stanie potwierdzić, że typ obiektu może zaoszczędzić Ci konieczności wykonywania wielu dereferencji wskaźnika, aby w końcu dojść do metody, którą chcesz wywołać.

Q2 Której implementacji Python użyto do implementacji PyPy?

Interpretator PyPy jest zaimplementowany w RPython, który jest statycznie typowanym podzbiorem Pythona (język, a nie interpreter CPython). - Patrz https://pypy.readthedocs.org/en/latest/architecture.html informacje .

Pytanie 3 A jakie są szanse, że PyPyPy lub PyPyPyPy pokonają swój wynik?

Zależy to od wdrożenia tych hipotetycznych tłumaczy. Jeśli jeden z nich na przykład wziął źródło, przeprowadził na nim jakąś analizę i przekształcił go bezpośrednio w ściśle określony kod asemblera po uruchomieniu, wyobrażam sobie, że byłby on znacznie szybszy niż CPython.

Aktualizacja: Ostatnio, na starannie dobrany przykład , pypy pokonał podobny program skompilowany z C gcc -O3. To przemyślany przypadek, ale zawiera pewne pomysły.

Pytanie 4 Dlaczego ktoś miałby spróbować czegoś takiego?

Z oficjalnej strony. https://pypy.readthedocs.org/en/latest/architecture.html#mission-statement

Naszym celem jest zapewnienie:

  • wspólne ramy tłumaczeń i wsparcia dla tworzenia
    implementacji języków dynamicznych, kładąc nacisk na czyste
    oddzielenie specyfikacji języka od
    aspektów implementacyjnych . Nazywamy to RPython toolchain_.

  • zgodna, elastyczna i szybka implementacja języka Python_, która wykorzystuje powyższy zestaw narzędzi, aby umożliwić nowe zaawansowane funkcje wysokiego poziomu bez konieczności kodowania szczegółów niskiego poziomu.

Dzięki oddzieleniu problemów w ten sposób nasza implementacja Pythona - i innych języków dynamicznych - jest w stanie automatycznie wygenerować kompilator Just-in-Time dla dowolnego języka dynamicznego. Pozwala także na podejście polegające na mieszaniu i dopasowywaniu do decyzji, w tym wielu, które historycznie znajdowały się poza kontrolą użytkownika, takich jak platforma docelowa, modele pamięci i wątków, strategie usuwania śmieci i zastosowane optymalizacje, w tym to, czy JIT w pierwszej kolejności.

Kompilator C gcc jest zaimplementowany w C. Kompilator Haskell GHC jest napisany w Haskell. Czy masz jakiś powód, dla którego interpreter / kompilator języka Python nie jest pisany w języku Python?

Noufal Ibrahim
źródło
82
W tej odpowiedzi całkowicie brakuje głównego wyjaśnienia, w jaki sposób PyPy jest szybki; chociaż wspomina, że ​​PyPy nie jest tak naprawdę zaimplementowany w Pythonie, ale w RPython, nie wskazuje, że kod RPython jest statycznie kompilowany i optymalizowany w celu uzyskania interpretera PyPy (okazuje się, że jest to również poprawny kod Pythona, który można uruchomić na górze) CPython znacznie wolniej). Zaimplementowali oni w „normalnym Pythonie” to „kompilator” RPython (środowisko tłumaczenia, o którym mowa w cytacie blokowym).
Ben
12
To zakopuje lede. Większość wydajności pochodzi z tłumaczenia na C (co sprawia, że ​​interpreter nie jest znacznie wolniejszy niż CPython) i JIT, który sprawia, że ​​gorące ścieżki są znacznie szybsze.
Tobu,
4
„Aktualizacja: Ostatnio, na starannie spreparowanym przykładzie, PyPy osiągnęło lepsze wyniki niż podobny program C skompilowany z gcc -O3”. A jeśli przeczytasz pierwszy komentarz pod tym postem, zobaczysz, że autor tego postu nie zna optymalizacji czasu łącza. Po włączeniu optymalizacji czasu łącza kod C działa szybciej.
Ali
2
Cóż, wpis na blogu był w 2011 r., A ta odpowiedź w 2014 r. Ponadto w komentarzu wspomniano o bibliotekach udostępnionych. Nie wiem, ile z tego (odpowiedź i post na blogu) jest prawidłowe. Wszystkie zaangażowane technologie bardzo się zmieniły w ciągu ostatnich kilku lat.
Noufal Ibrahim
1
Na dwóch starannie wykonanych przykładach Pypy jest szybszy niż równoważne C, każdy jest szybszy w testach porównawczych z bardzo konkretnego zestawu powodów. Po pierwsze, ponieważ Pypy jest wystarczająco inteligentny, aby zdawać sobie sprawę z tego, że liczenie w ścisłej pętli nigdy nie ma tej liczby, więc można go całkowicie usunąć (przejście JIT), a po drugie, ponieważ: Pypy JIT może „wstawiać się ponad granicami biblioteki”, biorąc pod uwagę przykład funkcji „printf” jest wyspecjalizowany, aby dosłownie móc emitować tylko liczbę całkowitą i eliminuje powtarzające się malloc (narzut związany z alokacją pamięci).
amcgregor
291

„PyPy to reimplementacja Pythona w Pythonie” jest dość mylącym sposobem opisania PyPy, IMHO, chociaż technicznie jest to prawdą.

Istnieją dwie główne części PyPy.

  1. Ramy tłumaczeń
  2. Tłumacz

Struktura tłumaczenia jest kompilatorem. Kompiluje kod RPython do C (lub innych celów), automatycznie dodając takie aspekty, jak wyrzucanie elementów bezużytecznych i kompilator JIT. Nie może obsługiwać dowolny kod Python, tylko RPython.

RPython jest podzbiorem normalnego Pythona; cały kod RPython jest kodem Python, ale nie na odwrót. Nie ma formalnej definicji RPython, ponieważ RPython jest w zasadzie tylko „podzbiorem Pythona, który może być przetłumaczony przez środowisko translacji PyPy”. Ale aby zostać przetłumaczonym, kod RPython musi być wpisany statycznie (typy są wywnioskowane, nie deklarujesz ich, ale wciąż jest to ściśle jeden typ na zmienną) i nie możesz robić takich rzeczy jak deklarowanie / modyfikowanie funkcji / klasy w czasie wykonywania.

Tłumacz to normalny interpreter języka Python napisany w RPython.

Ponieważ kod RPython jest normalnym kodem w języku Python, można go uruchomić na dowolnym interpretera języka Python. Ale żadne z twierdzeń dotyczących prędkości PyPy nie pochodzi z takiego działania; jest to tylko szybki cykl testowy, ponieważ tłumaczenie tłumacza zajmuje dużo czasu.

Mając to na uwadze, powinno być od razu oczywiste, że spekulacje na temat PyPyPy lub PyPyPyPy w rzeczywistości nie mają żadnego sensu. Masz tłumacza napisanego w RPython. Tłumaczysz go na kod C, który szybko wykonuje Python. Tam proces się kończy; nie ma już RPython do przyspieszenia poprzez ponowne przetworzenie.

Zatem „Jak to możliwe, że PyPy jest szybszy niż CPython” również staje się dość oczywiste. PyPy ma lepszą implementację, w tym kompilator JIT (uważam, że generalnie nie jest tak szybki bez kompilatora JIT, co oznacza, że ​​PyPy jest szybszy tylko dla programów podatnych na kompilację JIT). CPython nigdy nie został zaprojektowany jako wysoce optymalizująca implementacja języka Python (choć starają się, aby była to wysoce zoptymalizowana implementacja, jeśli podążasz za różnicą).


Naprawdę innowacyjny fragment projektu PyPy polega na tym, że nie piszą ręcznie skomplikowanych schematów GC ani kompilatorów JIT. Piszą interpreter stosunkowo prosto w RPython, a dla wszystkich RPython jest niższy poziom niż Python, to wciąż jest zorientowany obiektowo język zbierania śmieci, znacznie wyższy poziom niż C. Następnie struktura tłumaczenia automatycznie dodaje rzeczy takie jak GC i JIT. Tak więc ramy tłumaczenia są ogromnewysiłek, ale równie dobrze odnosi się do interpretera python PyPy, jednak zmieniają one swoją implementację, pozwalając na większą swobodę eksperymentowania w celu poprawy wydajności (bez martwienia się o wprowadzenie błędów GC lub aktualizację kompilatora JIT, aby poradzić sobie ze zmianami). Oznacza to również, że kiedy zaczną implementować interpreter języka Python3, automatycznie uzyska te same korzyści. I wszyscy inni tłumacze napisani w ramach PyPy (których jest wiele na różnych etapach języka polskiego). Wszyscy tłumacze korzystający ze środowiska PyPy automatycznie obsługują wszystkie platformy obsługiwane przez środowisko.

Tak więc prawdziwą zaletą projektu PyPy jest oddzielenie (w jak największym stopniu) wszystkich elementów wdrażania wydajnego niezależnego od platformy tłumacza dla dynamicznego języka. A potem wymyśl jedno dobre wdrożenie w jednym miejscu, które może być ponownie wykorzystane przez wielu tłumaczy. Nie jest to natychmiastowa wygrana, jak „mój program w Pythonie działa teraz szybciej”, ale jest to świetna perspektywa na przyszłość.

I może szybciej uruchomić Twój program Python (być może).

Ben
źródło
4
Nie mogłem nadążyć za różnicą :(
polvoazul,
37
@polvoazul Różnica między zoptymalizowaną implementacją języka a optymalizacją ? Cóż, kiedy mówię, że CPython jest dobrze zoptymalizowaną implementacją, mam na myśli, że programiści starają się, aby wewnętrzne algorytmy samego interpretera i wbudowane struktury danych działały wydajnie. Optymalizacji wdrażania, OTOH, by analizować użytkowników końcowych kod i spróbować dowiedzieć się sposobów, aby przekształcić go bardziej efektywnie wykonać.
Ben
23

PyPy jest zaimplementowany w Pythonie, ale implementuje kompilator JIT do generowania natywnego kodu w locie.

Powodem do wdrożenia PyPy na Pythonie jest prawdopodobnie to, że jest to po prostu bardzo produktywny język, zwłaszcza że kompilator JIT sprawia, że ​​wydajność języka hosta jest nieco nieistotna.

Marcelo Cantos
źródło
Czy JIT generuje kod Pythona działający na tym samym poziomie co PyPy, czy też generuje prawdziwy natywny kod działający na poziomie dowolnej implementacji Pythona, na której działa PyPy?
Edmund
3
Prawdziwy kod macierzysty (patrz tutaj ); Dokładniej 32-bitowy kod x86.
Marcelo Cantos,
11

PyPy jest napisany w języku Python z ograniczeniami. O ile mi wiadomo, nie działa na interpretera CPython. Python z ograniczeniami jest podzbiorem języka Python. AFAIK, interpreter PyPy jest kompilowany do kodu maszynowego, więc po zainstalowaniu nie używa interpretera python w czasie wykonywania.

Wydaje się, że twoje pytanie oczekuje, że interpreter PyPy działa na CPython podczas wykonywania kodu. Edycja: Tak, aby użyć PyPy, najpierw przetłumacz kod Pythona PyPy na C i buduj z gcc, na bajtowy kod jvm lub na kod CLI .Net. Zobacz Pierwsze kroki

bobpaul
źródło
8
PyPy będzie działał na CPython, ale w tym trybie nie zapewnia prędkości, jakiej można by oczekiwać. :-) codespeak.net/pypy/dist/pypy/doc/…
Frank V