PyPy - Wie kann es möglicherweise CPython schlagen?

264

Aus dem Google Open Source Blog :

PyPy ist eine Neuimplementierung von Python in Python, bei der mithilfe fortschrittlicher Techniken versucht wird, eine bessere Leistung als CPython zu erzielen. Viele Jahre harter Arbeit haben sich endlich ausgezahlt. Unsere Geschwindigkeitsergebnisse übertreffen CPython häufig und reichen von etwas langsameren bis zu 2-fachen Beschleunigungen bei echtem Anwendungscode und bis zu 10-fachen Beschleunigungen bei kleinen Benchmarks.

Wie ist das möglich? Mit welcher Python-Implementierung wurde PyPy implementiert? CPython ? Und wie hoch sind die Chancen, dass ein PyPyPy oder PyPyPyPy ihre Punktzahl übertrifft?

(In einem ähnlichen Zusammenhang ... warum sollte jemand so etwas versuchen?)

Agnel Kurian
quelle
43
Nitpick: PyPy ist PyPyPy. Stellen Sie sich das Präfix Py- * als Projektionsoperator vor.
u0b34a0f6ae
OK. PyPy sollte also CPython vorgezogen werden? Hat es irgendwelche Nachteile?
Balki
10
PyPy eignet sich hervorragend zur Laufzeitoptimierung, ist jedoch aufgrund seiner unterschiedlichen Innereien nicht mit mehreren gängigen C-Erweiterungen kompatibel .
Cees Timmerman
4
Fast jedem fehlt die Frage, wie theoretisch ein Geschwindigkeitsgewinn möglich ist. Aber denken Sie darüber nach: Python kann alles, genau wie eine Turing-Maschine. Es kann schließlich anrufen gcc. Sie können also auch Python-Code schreiben, der auf CPython ausgeführt wird, der einen anderen Python-Code interpretiert, in C übersetzt gccund das kompilierte Programm ausführt und dann ausführt. Und es könnte schneller sein, wenn der Code oft genug aufgerufen wird.
osa

Antworten:

155

Q1. Wie ist das möglich?

Die manuelle Speicherverwaltung (wie sie CPython beim Zählen ausführt) kann in einigen Fällen langsamer sein als die automatische Verwaltung.

Einschränkungen bei der Implementierung des CPython-Interpreters schließen bestimmte Optimierungen aus, die PyPy durchführen kann (z. B. feinkörnige Sperren).

Wie Marcelo erwähnte, ist die JIT. Wenn Sie den Typ eines Objekts im Handumdrehen bestätigen können, müssen Sie nicht mehr mehrere Zeiger-Dereferenzen durchführen, um schließlich zu der Methode zu gelangen, die Sie aufrufen möchten.

Q2. Mit welcher Python-Implementierung wurde PyPy implementiert?

Der PyPy-Interpreter ist in RPython implementiert, einer statisch typisierten Teilmenge von Python (der Sprache und nicht dem CPython-Interpreter). - Weitere Informationen finden Sie unter https://pypy.readthedocs.org/en/latest/architecture.html .

Q3. Und wie hoch sind die Chancen, dass ein PyPyPy oder PyPyPyPy ihre Punktzahl übertrifft?

Das würde von der Implementierung dieser hypothetischen Interpreten abhängen. Wenn einer von ihnen zum Beispiel die Quelle genommen, eine Art Analyse durchgeführt und sie nach einer Weile direkt in engen zielspezifischen Assembler-Code konvertiert hätte, wäre sie meiner Meinung nach ziemlich schneller als CPython.

Update: Vor kurzem hat PyPy in einem sorgfältig ausgearbeiteten Beispiel ein ähnliches C-Programm übertroffen, mit dem kompiliert wurde gcc -O3. Es ist ein erfundener Fall, zeigt aber einige Ideen.

Q4. Warum sollte jemand so etwas versuchen?

Von der offiziellen Seite. https://pypy.readthedocs.org/en/latest/architecture.html#mission-statement

Wir möchten bieten:

  • ein gemeinsames Übersetzungs- und Unterstützungs-Framework für die Erstellung von
    Implementierungen dynamischer Sprachen, das eine klare
    Trennung zwischen Sprachspezifikation und Implementierungsaspekten betont
    . Wir nennen das das RPython toolchain_.

  • Eine konforme, flexible und schnelle Implementierung der Python_-Sprache, die die oben genannte Toolchain verwendet, um neue erweiterte Funktionen auf hoher Ebene zu ermöglichen, ohne die Details auf niedriger Ebene codieren zu müssen.

Durch die Trennung von Bedenken auf diese Weise kann unsere Implementierung von Python - und anderen dynamischen Sprachen - automatisch einen Just-in-Time-Compiler für jede dynamische Sprache generieren. Es ermöglicht auch einen Mix-and-Match-Ansatz für Implementierungsentscheidungen, einschließlich vieler, die in der Vergangenheit außerhalb der Kontrolle eines Benutzers lagen, wie z. B. Zielplattform, Speicher- und Threading-Modelle, Garbage Collection-Strategien und angewendete Optimierungen, einschließlich der Frage, ob dies der Fall ist oder nicht eine JIT in erster Linie.

Der C-Compiler gcc ist in C implementiert. Der Haskell-Compiler GHC ist in Haskell geschrieben. Haben Sie einen Grund dafür, dass der Python-Interpreter / Compiler nicht in Python geschrieben wurde?

Noufal Ibrahim
quelle
82
In dieser Antwort fehlt die Haupterklärung dafür, wie schnell PyPy ist. Während erwähnt wird, dass PyPy nicht wirklich in Python implementiert ist, sondern in RPython, wird nicht darauf hingewiesen, dass RPython-Code statisch kompiliert und optimiert ist , um den PyPy-Interpreter zu erzeugen (es handelt sich zufällig auch um gültigen Python-Code, der oben ausgeführt werden kann von CPython viel langsamer). Was sie in "normalem Python" implementiert haben, ist der RPython "Compiler" (das Übersetzungsframework, auf das im Blockzitat verwiesen wird).
Ben
12
Dies begräbt die Lede. Der größte Teil der Leistung kommt von der Übersetzung nach C (wodurch der Interpreter nicht viel langsamer als CPython ist) und JIT, wodurch Hot Paths viel schneller werden.
Tobu
4
"Update: Vor kurzem hat PyPy in einem sorgfältig ausgearbeiteten Beispiel ein ähnliches C-Programm übertroffen, das mit gcc -O3 kompiliert wurde." Und wenn Sie den ersten Kommentar unter diesem Beitrag lesen, werden Sie feststellen, dass der Verfasser dieses Beitrags die Optimierung der Verbindungszeit nicht kennt. Wenn die Optimierung der Verbindungszeit aktiviert ist, wird der C-Code schneller ausgeführt.
Ali
2
Nun, der Blog-Beitrag war im Jahr 2011 und diese Antwort im Jahr 2014. In dem Kommentar werden auch gemeinsam genutzte Bibliotheken erwähnt. Ich weiß nicht, wie viel davon (Antwort und Blog-Beitrag) gültig ist. Alle beteiligten Technologien haben sich in den letzten Jahren stark verändert.
Noufal Ibrahim
1
Bei den beiden sorgfältig ausgearbeiteten Beispielen, bei denen Pypy schneller als äquivalentes C ist, ist jedes aus einer Reihe von Gründen im Benchmark schneller. Das erste, weil Pypy klug genug ist, um zu erkennen, dass die Zählung mit engen Schleifen niemals verwendet wird, so dass es vollständig gelöscht werden kann (JIT-Pass), das zweite für eine Kombination aus: weil das Pypy-JIT "über Bibliotheksgrenzen hinweg inline" kann Das Beispiel der "printf" -Funktion ist darauf spezialisiert, buchstäblich nur eine Ganzzahl ausgeben zu können, und eliminiert wiederholtes Malloc (Speicherzuweisungsaufwand).
Amcgregor
291

"PyPy ist eine Neuimplementierung von Python in Python" ist eine ziemlich irreführende Art, PyPy zu beschreiben, IMHO, obwohl es technisch wahr ist.

Es gibt zwei Hauptteile von PyPy.

  1. Der Übersetzungsrahmen
  2. Der Dolmetscher

Das Übersetzungsframework ist ein Compiler. Es kompiliert RPython- Code bis auf C (oder andere Ziele) und fügt automatisch Aspekte wie die Garbage Collection und einen JIT-Compiler hinzu. Es kann keinen beliebigen Python-Code verarbeiten, nur RPython.

RPython ist eine Teilmenge von normalem Python. Der gesamte RPython-Code ist Python-Code, aber nicht umgekehrt. Es gibt keine formale Definition von RPython, da RPython im Grunde nur "die Teilmenge von Python ist, die vom PyPy-Übersetzungsframework übersetzt werden kann". Um übersetzt zu werden, muss RPython-Code statisch typisiert sein (die Typen werden abgeleitet, Sie deklarieren sie nicht, aber es ist immer noch nur ein Typ pro Variable), und Sie können keine Funktionen wie das Deklarieren / Ändern von Funktionen ausführen. Klassen auch zur Laufzeit.

Der Interpreter ist dann ein normaler Python-Interpreter, der in RPython geschrieben ist.

Da RPython-Code normaler Python-Code ist, können Sie ihn auf jedem Python-Interpreter ausführen. Aber keiner der Geschwindigkeitsansprüche von PyPy beruht darauf, dass es so läuft. Dies ist nur für einen schnellen Testzyklus gedacht, da die Übersetzung des Dolmetschers lange dauert .

Vor diesem Hintergrund sollte sofort klar sein, dass Spekulationen über PyPyPy oder PyPyPyPy eigentlich keinen Sinn ergeben. Sie haben einen in RPython geschriebenen Interpreter. Sie übersetzen es in C-Code, der Python schnell ausführt. Dort stoppt der Prozess; Es gibt kein RPython mehr, das durch erneutes Verarbeiten beschleunigt werden könnte.

"Wie ist es möglich, dass PyPy schneller als CPython ist?" Wird auch ziemlich offensichtlich. PyPy hat eine bessere Implementierung, einschließlich eines JIT-Compilers (ohne den JIT-Compiler ist es meiner Meinung nach im Allgemeinen nicht ganz so schnell, was bedeutet, dass PyPy nur für Programme schneller ist, die für die JIT-Kompilierung anfällig sind). CPython wurde nie als hochoptimierende Implementierung der Python-Sprache entwickelt (obwohl sie versuchen, sie zu einer hochoptimierten Implementierung zu machen , wenn Sie dem Unterschied folgen).


Das wirklich Innovative am PyPy-Projekt ist, dass sie keine ausgeklügelten GC-Schemata oder JIT-Compiler von Hand schreiben. Sie schreiben den Interpreter relativ einfach in RPython, und für alle RPython-Versionen ist es eine niedrigere Ebene als Python. Es ist immer noch eine objektorientierte, durch Müll gesammelte Sprache, viel höher als C. Dann fügt das Übersetzungs-Framework automatisch Dinge wie GC und JIT hinzu. Das Übersetzungs-Framework ist also riesigDies gilt jedoch auch für den PyPy-Python-Interpreter. Er ändert jedoch seine Implementierung und ermöglicht so viel mehr Freiheit beim Experimentieren, um die Leistung zu verbessern (ohne sich Gedanken über die Einführung von GC-Fehlern oder die Aktualisierung des JIT-Compilers zu machen, um mit den Änderungen fertig zu werden). Dies bedeutet auch, dass bei der Implementierung eines Python3-Interpreters automatisch dieselben Vorteile erzielt werden. Und alle anderen Interpreten, die mit dem PyPy-Framework geschrieben wurden (von denen es eine Reihe in verschiedenen Phasen der Politur gibt). Alle Interpreter, die das PyPy-Framework verwenden, unterstützen automatisch alle vom Framework unterstützten Plattformen.

Der wahre Vorteil des PyPy-Projekts besteht also darin, alle Teile der Implementierung eines effizienten plattformunabhängigen Interpreters für eine dynamische Sprache (so weit wie möglich) zu trennen. Und dann finden Sie eine gute Implementierung an einem Ort, die von vielen Dolmetschern wiederverwendet werden kann. Das ist kein sofortiger Gewinn wie "Mein Python-Programm läuft jetzt schneller", aber es ist eine großartige Perspektive für die Zukunft.

Und es kann Ihr Python-Programm (vielleicht) schneller ausführen.

Ben
quelle
4
Ich konnte dem Unterschied nicht folgen :(
polvoazul
37
@polvoazul Der Unterschied zwischen einer optimierten und einer optimierten Sprachimplementierung ? Wenn ich sage, dass CPython eine gut optimierte Implementierung ist, meine ich, dass die Entwickler versuchen, die internen Algorithmen des Interpreters selbst und die eingebauten Datenstrukturen effizient laufen zu lassen. Eine optimierende Implementierung, OTOH, würde den Code des Endbenutzers analysieren und versuchen, Wege zu finden, um ihn zu transformieren und effizienter auszuführen.
Ben
23

PyPy ist in Python implementiert, implementiert jedoch einen JIT-Compiler, um nativen Code im laufenden Betrieb zu generieren.

Der Grund für die Implementierung von PyPy auf Python ist wahrscheinlich, dass es sich lediglich um eine sehr produktive Sprache handelt, zumal der JIT-Compiler die Leistung der Hostsprache etwas irrelevant macht.

Marcelo Cantos
quelle
Generiert die JIT Python-Code, der auf derselben Ebene wie PyPy ausgeführt wird, oder generiert sie echten nativen Code, der auf der Ebene der Python-Implementierung ausgeführt wird, auf der PyPy ausgeführt wird?
Edmund
3
Echter nativer Code (siehe hier ); 32-Bit-x86-Code um genau zu sein.
Marcelo Cantos
11

PyPy ist in Restricted Python geschrieben. Soweit ich weiß, läuft es nicht auf dem CPython-Interpreter. Eingeschränktes Python ist eine Teilmenge der Python-Sprache. AFAIK, der PyPy-Interpreter wird zu Maschinencode kompiliert, sodass bei der Installation zur Laufzeit kein Python-Interpreter verwendet wird.

Ihre Frage scheint zu erwarten, dass der PyPy-Interpreter während der Ausführung von Code auf CPython ausgeführt wird. Bearbeiten: Ja, um PyPy zu verwenden, übersetzen Sie zuerst den PyPy-Python-Code, entweder in C und erstellen mit gcc, in JVM-Byte-Code oder in .NET-CLI-Code. Siehe Erste Schritte

Bobpaul
quelle
8
PyPy läuft auf CPython, bietet jedoch in diesem Modus nicht die gewünschten Geschwindigkeitsgewinne. :-) codespeak.net/pypy/dist/pypy/doc/…
Frank V