3 Punkte von GN⁺ 2025-12-26 | 1 Kommentare | Auf WhatsApp teilen
  • Der Tail-Calling-Interpreter von CPython zeigt unter Windows x86-64 etwa 15 % bessere Leistung als die bisherige Methode
  • Auch unter macOS AArch64 (XCode Clang) wurde ein Leistungsplus von etwa 5 % bestätigt; unter Windows kommt eine experimentelle Funktion von MSVC 2026 zum Einsatz
  • Im pyperformance-Benchmark zeigten die meisten Tests Geschwindigkeitsgewinne, einige verbesserten sich um bis zu 78 %
  • Als Hauptursachen für den Performance-Gewinn gelten zurückgesetzte Compiler-Optimierungsheuristiken und verbessertes Inlining
  • Mit der offiziellen Veröffentlichung von Python 3.15 soll dies standardmäßig in Builds auf Basis von Visual Studio 2026 aktiviert werden

Performance-Verbesserung des Tail-Calling-Interpreters

  • Der Tail-Calling-Interpreter von CPython wurde unter Windows x86-64 als etwa 15 % schneller als der bisherige Switch-Case-Interpreter gemessen
    • Laut pyperformance liegt das geometrische Mittel bei einer Verbesserung von 15–16 %
    • Einige Benchmarks zeigten bis zu 78 % mehr Geschwindigkeit, in wenigen Fällen war die Ausführung 60 % langsamer
  • Unter macOS AArch64 (XCode Clang) wurde ebenfalls ein Leistungsplus von rund 5 % festgestellt
  • Diese Ergebnisse gelten unter der Annahme, dass sich im Entwicklungszyklus von Python 3.15 daran nichts mehr ändert

Vergleich der Interpreter-Architekturen

  • C-basierte Implementierungen von Interpretern lassen sich in drei Varianten einteilen: switch-case, computed goto und tail-call threaded
    • switch-case: Verzweigungsbehandlung pro Instruktion
    • computed goto: GCC-/Clang-Erweiterung mit direktem Sprung zur Verzweigungsadresse
    • tail-call threaded: Jeder Bytecode-Handler wird in eine eigene Funktion aufgeteilt und per Tail Call an die nächste Funktion übergeben
  • Früher garantierten C-Compiler keine Tail-Call-Optimierung, wodurch ein Risiko für Stack Overflow bestand
  • Mit den Attributen __attribute__((musttail)) von Clang und [[msvc::musttail]] von MSVC sind erzwungene Tail Calls möglich geworden
Anzeige

Build-Ergebnisse mit MSVC 2026 für Windows

  • In einem CPython-Build mit experimentellen MSVC-Funktionen zeigten die meisten Benchmarks höhere Geschwindigkeit
    • Beispielergebnisse:
      • spectralnorm: 1,48-fach
      • nbody: 1,35-fach
      • bm_django_template: 1,18-fach
      • xdsl: 1,14-fach
  • Dies wurde offiziell in das Dokument „What’s New“ für Python 3.15 aufgenommen
    • In Builds mit Visual Studio 2026 (MSVC 18) ist der Tail-Calling-Interpreter verfügbar
    • Reine Python-Bibliotheken werden um etwa 15 % beschleunigt, kleine Skripte um bis zu 40 %

Ursachen des Performance-Gewinns

  • Tail Calling setzt die Optimierungsheuristiken des Compilers zurück und fördert dadurch effizientere Code-Erzeugung
  • Die bisherige CPython-Interpreter-Schleife bestand aus einer einzigen Funktion mit rund 12.000 Zeilen, wodurch Inlining-Optimierungen häufig scheiterten
    • In vielen Fällen verweigerte der Compiler Inlining, um eine Vergrößerung des Codes zu vermeiden
    Anzeige
  • Beim Tail-Calling-Ansatz werden Funktionen aufgeteilt, sodass einfache Funktionen inline verarbeitet werden können
    • Als Beispiel wird eine einfache Funktion wie PyStackRef_CLOSE_SPECIALIZED inline eingebettet
  • Dasselbe Phänomen wurde auch bei Builds mit PGO (profilgesteuerter Optimierung) beobachtet

Build- und Nutzungsmethode

  • Derzeit ist nur ein Build aus dem Quellcode möglich
    • In einer Visual-Studio-2026-Umgebung erfolgt der Build mit folgendem Befehl
      $env:PlatformToolset = "v145"
      ./PCbuild/build.bat --tail-call-interp -c Release -p x64 --pgo
      
  • Sobald sich die Entwicklung von Python 3.15 stabilisiert, ist eine offizielle Binärverteilung vorgesehen

1 Kommentare

 
GN⁺ 2025-12-26
Hacker-News-Kommentare
  • Hier ist der zentrale Codeausschnitt, der im Blogpost hätte enthalten sein sollen.
    Er zeigt ein Beispiel für die Unterschiede in der Definition der Attribute musttail und preserve_none zwischen MSVC und Clang.
    Diese Attribute müssen an den Funktionsdeklarator angehängt werden und funktionieren nicht an der Position von Funktionsspezifizierern.
    Link zum relevanten Code
    Es klingt ein wenig so, als würde Microsoft solche nicht öffentlichen Features nur Projekten mitteilen, die sie für wichtig halten.
    • Ich lag falsch. [[msvc::musttail]] war tatsächlich ein offiziell dokumentiertes Attribut.
      Ich werde den Blogpost entsprechend korrigieren.
      Zugehöriger HN-Kommentar
    • Es wird die Frage aufgeworfen: „Haben sie es mitgeteilt, weil es wichtig ist, oder weil es ihnen selbst nützt?“
  • Das erinnert an den Fall bei Python 3.14, als wegen eines LLVM-19-Bugs irrtümlich eine Leistungssteigerung gemeldet wurde; hoffentlich passiert das diesmal nicht.
    Nach dem Lesen des Artikels wirkt der Ansatz aber solide, weil Transparenz und schnelles Feedback priorisiert wurden.
    Eine Verifikation mit Cross-Compilern oder ein unabhängiges Audit wäre noch besser, aber dank der vollständigen Transparenz des Autors erscheint es vertrauenswürdig.
    • Der Autor erinnert sich, dass der damalige Fehler im Nachhinein eher ein glücklicher Unfall war.
      Weil es früh veröffentlicht wurde, entdeckte Nelson den Clang-19-Bug, sodass er noch vor dem offiziellen Release behoben werden konnte.
      Diesmal ist er zuversichtlicher, weil es zwei Verbesserungen gibt: Dispatch-Logik und Inlining.
      MSVC kann unter bestimmten Bedingungen einen Switch-Case-Interpreter in Threaded Code umwandeln, aber CPython ist zu komplex, sodass diese Optimierung dort nicht greift.
      Der Tail-Call-Ansatz gibt stattdessen dem C-Code-Autor mehr Kontrolle.
      Verwandte Referenzen: Bedingungen für MSVC Threaded Code, Issue zu forceinline
    • Ein Vorteil des neuen Designs ist, dass es weniger von der Launenhaftigkeit von Compiler-Optimierungen abhängt.
      Früher hingen Optimierungen wie Tail Duplication vom Urteil des Compilers ab, jetzt kann der Interpreter die gewünschte Form des Maschinencodes direkt ausdrücken.
      Link zur früheren Diskussion
  • Es wird ein Vortrag über frühere Compiler-Probleme geteilt: EuroPython-2025-Vortrag
  • Ich entwickle nach langer Zeit wieder eine GUI-App für Windows mit Python.
    Statt C#/MAUI habe ich Python gewählt, weil das VS-Ökosystem viel zu schwergewichtig ist.
    Tkinter war unbequem, und Qt hatte eine hohe Lernhürde, deshalb nutze ich die Kombination wxGlade + wxPython.
    Ich brauche nur eine einzelne per pip installierbare Abhängigkeit, und mir gefällt das Pythonic-Gefühl dabei.
    Verbesserungen an der Windows-Laufzeit sind daher sehr willkommen.
    • Ich bevorzuge die Kombination Python + Qt/PySide.
      Mit QtCreator kann man schnell die UI bauen und dann die Logik in Python anhängen, was die Entwicklung sehr beschleunigt.
    • pyfltk ist auch eine Empfehlung. Unter GNU/Linux war es ziemlich gut.
    • Wenn die GUI wichtig ist, könnte auch LINQPad einen Blick wert sein. Es liegt irgendwo zwischen Scripting und schwergewichtigeren Lösungen.
    • Ich empfehle ImGui-Bindings für Python.
      Anders als Tkinter oder Qt arbeitet es nicht im Retained Mode, sondern im Immediate Mode, was besonders für internes Tooling nützlich ist.
      imgui_bundle-Projekt
  • Jemand fragt: „Ist das nicht eine Optimierungsaufgabe mit eher niedrigem Schwierigkeitsgrad?“, und wundert sich, warum die Interpreter-Schleife noch nicht vollständig optimiert ist.
    Er sagt, er hätte erwartet, dass sie für die wichtigsten ISAs in Assembler geschrieben sei.
    • Eher im Gegenteil zeigt dieses Update, dass die Schleife bereits extrem stark optimiert ist.
      [[msvc::musttail]] ist ein brandneues Attribut, das erst in MSVC 14.50 hinzugefügt wurde, das letzten Monat erschienen ist, und das CPython-Team hat es innerhalb weniger Wochen für Leistungsgewinne genutzt.
      MSVC-musttail-Dokumentation
    • Python zielt von Anfang an eher auf Einfachheit als auf Geschwindigkeit.
      Guido priorisierte die Einfachheit des Codes, weshalb ein JIT spät kam; später folgten Versuche wie PEP 744 (JIT Compilation).
    • Man sollte an Open Source keine überzogenen Erwartungen haben.
      Assembler-Optimierungen sind ein Wartungsalbtraum, und der eigentliche Flaschenhals von Python ist das Paketierungssystem.
    • Wer wirklich leistungssensibel ist, führt Python ohnehin nicht unter Windows aus, heißt es.
  • Es wird gefragt: „Warum ist der Python-Interpreter viel langsamer als V8?“
    • JavaScript nutzt JIT-Compilation, CPython jedoch nicht.
      PyPy ist dank JIT schneller, aber nicht kompatibel mit C-Erweiterungen.
      Auch das Threading-Modell von Python erschwert Optimierungen.
      JS ist dagegen Single-Threaded und dadurch einfacher.
      Da Python auf C-Erweiterungen ausweichen kann, gab es weniger Druck, CPython selbst zu optimieren.
    • Der große Unterschied liege bei Personalstärke und Qualität bei Google.
      Außerdem kann CPython wegen seines riesigen Ökosystems an C-Erweiterungen die Kompatibilität nicht aufbrechen.
      V8 konnte seine internen Strukturen dagegen frei verändern.
    • Python ist viel dynamischer; sogar der Attributzugriff läuft über das Descriptor-Protokoll.
      Außerdem muss eine stabile C-ABI erhalten bleiben, was es einem JIT erschwert, den Code frei zu analysieren.
    • Python ist eine deutlich dynamischere Sprache als JS, und durch FFI-Bindings sind interne Änderungen eingeschränkt.
      Es wird auf Fälle verwiesen, in denen PyPy große Mühe hatte, diese Einschränkungen einzuhalten.
    • JS wurde mit gewaltigen Ressourcen optimiert, damit Google das Web dominieren kann, während bei Python mehr Ressourcen in die Weiterentwicklung der Sprache geflossen sind.
      Außerdem muss JS nur reines JS unterstützen, Python dagegen ein Ökosystem externer Erweiterungen, was Optimierungen stark einschränkt.
  • Die neuen Benchmark-Grafiken seien interessant, und jemand fragt, mit welchem Tool sie erzeugt wurden.
    Dazu teilt er, dass er mit mitata bereits die Performance von JS-Bibliotheken gemessen hat.
    PR zur Optimierung von Immer JS
    • Bei der Grafik handelt es sich um einen Violin Plot.
      Wikipedia-Erklärung, Matplotlib-Beispiel
      Er visualisiert die Verteilung symmetrisch, aber Glättung kann die tatsächliche Verteilung verzerren, und es gibt auch Kritik, dass er Platz verschwendet.
      In dieser HN-Diskussion wurde auch die Meinung vertreten, ein Half-Violin-Plot sei besser.
      Beispielbild
  • Es wird erwähnt, dass Matt Godbolt gesagt habe, ein tail-call-basierter Interpreter passe besser zum Branch Predictor der CPU.
  • Jemand merkt an, dass der erste Satz des Artikels zwei Tippfehler enthält, und fragt, ob das vielleicht absichtliche Fehler waren, damit es wie nicht von KI erzeugt wirkt.
    • Der Autor antwortet: „Danke, habe es korrigiert.“
    • Ein anderer Nutzer scherzt, dass man einen Text einfach selbst schreiben müsse, wenn er nicht nach KI aussehen solle.
      Dabei werden typische Merkmale von KI-Texten persifliert, etwa kurze Absätze, übertrieben positiver Ton und mangelnde Tiefe.
  • Es wird gefragt: „Wenn das Python-Team Tail Calls für nützlich hält, bekommt dann vielleicht auch die Sprache selbst Tail-Call-Unterstützung?“