5 Punkte von GN⁺ 2025-05-17 | 1 Kommentare | Auf WhatsApp teilen
  • Free-Threaded Python wurde so konzipiert, dass es Multicore-Hardware effizient nutzen kann
  • In CPython 3.14 wurden Thread-Sicherheit und Performance zentraler Module deutlich verbessert
  • Es gibt weiterhin viele wichtige Pakete, die Free-Threaded-Builds noch nicht unterstützen
  • Alle können durch Berichte aus realen Einsatzumgebungen und Beiträge aus der Community zur Weiterentwicklung beitragen

Überblick

Letzte Woche wurde CPython 3.14.0b1 veröffentlicht, und in dieser Woche beginnt PyCon 2025 in Pittsburgh.
Diese beiden Ereignisse sind wichtige Meilensteine für die Bereitstellung und Stabilisierung von Free-Threaded Python.
Dieser Beitrag blickt auf das vergangene Jahr zurück und erklärt, wie das Team von Quansight eine Schlüsselrolle dabei spielte, den Free-Threaded-Build experimentell auf reale Produktions-Workflows mit komplexen Abhängigkeiten anzuwenden.

Bedeutung und Notwendigkeit von Free-Threaded Python

  • Die Unterstützung für Free-Threaded Python ermöglicht die volle Nutzung der Rechenressourcen moderner Hardware, auf der Multicore-CPUs und GPUs allgegenwärtig sind
  • Beim bisherigen GIL-Ansatz (Global Interpreter Lock) waren Umgehungslösungen und zusätzliches Tuning nötig, um parallele Algorithmen vollständig zu nutzen
  • Statt des Moduls threading wurde meist multiprocessing verwendet, doch das verursacht hohe Prozess-Startkosten und ist auch bei Datenkopien ineffizient
  • Wenn Python-Pakete nativen Code enthalten, sind sie nicht automatisch mit Free-Threaded-Builds kompatibel; zur Gewährleistung von Thread-Sicherheit ist daher zwingend ein Code-Audit erforderlich
  • Die Entfernung des GIL erforderte tiefgreifende strukturelle Änderungen am CPython-Interpreter und legte zugleich strukturelle Probleme bestehender Pakete offen

Wichtige Erfolge

  • Gemeinsam mit dem Python-Runtime-Team von Meta wurden Beiträge zur Unterstützung von Free-Threaded Python in verschiedenen Paketen und Projekten geleistet, darunter:
    • Packaging- und Workflow-Tools wie meson, meson-python, setup-python GitHub Actions, packaging, pip und setuptools
    • Binding-Generatoren wie Cython, pybind11, f2py und PyO3
    • Zentrale Pakete des PyData-Ökosystems wie NumPy, SciPy, PyArrow, Matplotlib, pandas, scikit-learn und scikit-image
    • Wichtige stark nachgefragte Abhängigkeiten auf PyPI wie Pillow, PyYAML, yarl, multidict und frozenlist
  • An beliebten Paketen ohne Unterstützung (CFFI, cryptography, PyNaCl, aiohttp, SQLAlchemy, grpcio usw.) sowie an Machine-Learning-Bibliotheken (safetensors, tokenizers usw.) wird schrittweise weitergearbeitet
  • Die CPython-Core-Entwickler im Quansight-Team haben für Version 3.14 unter anderem folgende Verbesserungen eingebracht:
    • Das Modul warnings arbeitet in Free-Threaded-Builds standardmäßig thread-sicher
    • Schwerwiegende Probleme bei der Thread-Sicherheit von asyncio wurden verbessert und die parallele Skalierbarkeit erhöht
    • Umfassende Verbesserungen der Thread-Sicherheit im ctypes-Modul
    • Leistungsverbesserungen beim Free-Threaded-Garbage Collector
    • Optimierungen des Schemas deferred reference counting und des adaptive specializing interpreter
    • Zahlreiche Bugfixes und zusätzliche Verbesserungen der Thread-Sicherheit
  • Außerdem wurde ein umfassender Leitfaden1 für die Unterstützung von Free-Threaded Python erstellt, der künftig für noch mehr Pakete als praxisnahe Dokumentation dienen kann

Stand des Free-Threaded-Python-Ökosystems

  • Vor einem Jahr (zum Zeitpunkt der Veröffentlichung von 3.13.0b1) war die Installation der meisten Python-Pakete auf Free-Threaded-Builds grundsätzlich kaputt
  • Die Ursachen für Build-Fehler waren meist keine fundamentalen Probleme, sondern nicht unterstützte Standardoptionen oder kleine Annahmen, die nicht mehr galten
  • Im vergangenen Jahr wurden gemeinsam mit der Community viele Probleme behoben; insbesondere die offizielle Unterstützung in Cython 3.1.0 war ein großer Wendepunkt
  • Noch immer gibt es Pakete mit kompiliertem Code, die jedoch keine Free-Threaded-Wheels bereitstellen.
    Ihr Fortschritt lässt sich in manuell und automatisch gepflegten Tracking-Tabellen2 verfolgen

Aktuelle Herausforderungen

  • Derzeit befinden sich Free-Threaded-Python-Builds in einer Phase, in der Experimente und Feedback aus realen Workflows benötigt werden
  • Gerade bei Workflows mit hohen Kosten für die Nutzung von Multiprocessing ist Performance-Gewinn möglich, doch dafür sind detaillierte Audits zur Thread-Sicherheit jedes Pakets unverzichtbar
  • Viele Bibliotheken stellen mutierbare Datenstrukturen bereit, ohne Thread-Sicherheit ausreichend zu dokumentieren oder tatsächlich zu garantieren
  • Bei großen Paketen mit viel Legacy-Code verzögert sich die Unterstützung oft, weil es an Menschen fehlt, die den Code vollständig überblicken können
  • Auf Community-Ebene sind Anstrengungen nötig, um die Nachhaltigkeit der Wartung zentraler Pakete zu sichern

Wie man beitragen kann

  • Das offizielle Handbuch mit dem Leitfaden für Beiträge kann als Einstieg dienen
  • Ökosystemweite Issues und zentrale Kompatibilitätsdokumente werden im Repository free-threaded-compatibility5 gepflegt
  • Diskussionen und Beiträge sind auch über den von Quansight-Labs betreuten Community-Discord6 möglich

Ankündigung zum geplanten PyCon-Vortrag

  • Der Autor des Beitrags und sein Teamkollege Lysandros Nikolaou werden auf der PyCon 2025 sprechen
  • Geplant ist, praxisnahe Portierungsbeispiele und Know-how aus eigener Erfahrung zu teilen; außerdem soll eine Aufzeichnung auf YouTube bereitgestellt werden
  • Man ist überzeugt, dass Free-Threaded-Builds die Zukunft der Python-Sprache sind, und freut sich darauf, zu ihrer Verwirklichung beizutragen
  • Die Hoffnung ist, dass die heutigen Bemühungen zu einem Wendepunkt für die Zukunft der vielfältigen und umfangreichen Pakete werden, die täglich von Millionen Entwicklern genutzt werden

1 Kommentare

 
GN⁺ 2025-05-17
Hacker-News-Kommentare
  • Viele nutzen Multiprocessing und weisen darauf hin, dass das Erzeugen von Prozessen teuer ist

    • Es gibt die Funktion SharedMemory, und es ist unklar, warum sie nicht häufiger genutzt wird

    • Es wird betont, dass die Erfahrungen mit ShareableList gut waren

    • Unter Unix liegt die Geschwindigkeit der Prozesserzeugung bei unter 1 ms

      • Das Starten eines PYTHON-Interpreterprozesses kann jedoch je nach Anzahl der Imports 30 ms bis 300 ms dauern
      • Da hier ein Unterschied um ein bis zwei Größenordnungen besteht, sind genaue Zahlen wichtig
      • CGI ist in diesem Punkt eine Ausnahme; mit C, Rust und Go gibt es dieses Problem nicht
      • Als Beispiel wird genannt, dass auch sqlite.org ein separates Prozessmodell pro Anfrage verwendet
    • ShareableList kann nur atomare Skalare sowie Bytes und Strings gemeinsam nutzen

      • Strukturierte Python-Objekte verursachen Kosten durch Serialisierung wie pickle dump sowie durch prozessweise duplizierten Speicher
    • Es wurden große Erfolge beim Teilen von NumPy-Arrays erzielt

      • Explizites Sharing ist keine große Last im Vergleich zur Schwierigkeit, Probleme zu debuggen, die durch versehentliches Sharing zwischen Threads entstehen
      • Viele überschätzen, wie viel besser Threads im Vergleich zu Multiprocessing seien
      • Es besteht die Sorge, dass mit Wegfall des GIL mehr zufällige segfaults debuggt werden müssen
      • Es wird erwähnt, dass sich kaum jemand stark darüber beschwert hat, dass JavaScript kein auf Shared Memory basierendes Threading unterstützt
      • Eine Deutung ist, dass JavaScript schnell genug ist und daher seltener Bedarf daran hat
      • Gewünscht wird mehr Einsatz für die Verbesserung der grundlegenden Python-Performance
    • Prozesse sterben unabhängig voneinander; wenn also ein Prozess stirbt, während er mit gehaltenem Lock eine Shared-Memory-Datenstruktur verändert, ist die Wiederherstellung schwierig

      • Als Beispiel werden die Shared-Memory-Strukturen von Postgres und die Notwendigkeit genannt, alle Backend-Prozesse zu beenden
      • Bei Threads tritt dieses Problem gefühlt seltener ins Bewusstsein, weil sie gemeinsam sterben
    • Shared Memory funktioniert nur auf dedizierter Hardware

      • In Umgebungen wie AWS Fargate gibt es keinen Shared Memory; stattdessen müssen Netzwerk oder Dateisystem verwendet werden, was die Latenz erhöht
      • Prozessduplizierung per fork bringt andere Probleme mit sich
      • Aus praktischer Erfahrung seien Green Threads und das Actor-Modell deutlich effektiver gewesen
  • Es wird gefragt, ob das Entfernen des GIL außer echter Parallelisierung noch andere Auswirkungen auf multithreadeten Python-Code hat

    • Das Verständnis ist, dass der GIL nicht deshalb beibehalten wurde, weil Multithreading auf ihn angewiesen wäre, sondern weil seine Entfernung die Implementierung des Interpreters und der C-Erweiterungen erschwert und Single-Thread-Code verlangsamt

    • Es wird gefragt, ob Free-Threaded Python weiterhin dieselbe bisherige Garantie bietet, an Bytecode-Grenzen jederzeit präemptiert werden zu können

    • Oder ob man anders programmieren muss, etwa mit mehr Locks

    • Free-Threaded Python bietet größtenteils dieselben Garantien

      • Ohne Free-Threading nutzen Leute Threading allerdings seltener, und Bugs durch Präemption an solchen Grenzen treten in der Praxis nicht so oft auf
      • Mit der Einführung von Free-Threading werden mehr Bugs sichtbar werden
      • Dafür entfällt die Notwendigkeit von Multiprozess-Workarounds, wodurch User-Code einfacher wird; der höhere Aufwand im Interpreter wird als lohnend angesehen
      • Das Problem der komplexeren C-Erweiterungen sei bei Sub-Interpretern noch gravierender als bei Free-Threading; das NumPy-Team habe klar gesagt, dass es Sub-Interpreter nicht unterstützen könne
      • NumPy unterstützt Free-Threading bereits, verbleibende Bugs werden noch behoben
      • Ein leichter Verlust bei der Single-Thread-Geschwindigkeit im einstelligen Prozentbereich wird als akzeptabler Trade-off gesehen
    • Mehrkernnutzung ist möglich, allerdings bei geringerer Leistung pro Thread und nötiger Überarbeitung von Bibliotheken

      • In Experimenten mit PyTorch wurden 10-facher CPU-Einsatz, aber nur halb so viel Durchsatz beobachtet
      • Es wird erwartet, dass sich das mit der Zeit verbessert, und nach 20 Jahren Wartezeit sei das dennoch sehr erfreulich
    • Race Conditions könnten häufiger auftreten, daher ist beim Schreiben von multithreadetem Python mehr Sorgfalt nötig, wenn Zuverlässigkeit garantiert werden soll

  • Es wird berichtet, dass Microsoft das Faster-Python-Team aufgelöst hat

    • Offenbar wurde das Team wegen verfehlter Erwartungen an die Geschäftszahlen 2025 nicht weitergeführt

    • Es bleibt abzuwarten, ob weitere Performance-Verbesserungen in CPython einfließen oder ob andere Unternehmen die Förderung übernehmen

    • Facebook (Meta) scheint weiterhin teilweise zu fördern

    • Es wird erwähnt, dass Microsofts Zeitplan im Vergleich zu seinen Zusagen stark in Verzug geraten sei

      • Inzwischen kenne man dort wohl ernsthafte politische und Governance-Probleme; fähige Mitarbeiter wollten vermutlich nicht unnötig beitragen und dann erleben, wie die Gruppe diffamiert wird
      • Die CPython-Organisation wird kritisiert, zu viel zu versprechen, gefügigen Personen Arbeit zuzuschieben und kompetente Widersprecher hinauszudrängen
      • Früher habe es diese Probleme nicht gegeben; die aktuelle Situation sei selbst verschuldet
    • Dieses Ergebnis sei zwar bedauerlich, bestätige aber die eigene Erwartung, Microsofts langfristigen Zusagen nicht zu trauen

    • Kürzlich habe es auch das Gerücht gegeben, Google habe sein gesamtes Python-Entwicklungsteam entlassen

      • Es wird gefragt, ob es bei beiden einen zeitbedingten Grund oder einen gemeinsamen Nenner gibt
    • Sehr bedauerlich, aber mit einer Anspielung darauf, dass nach „embrace & extend“ nur noch eines übrig bleibe

  • Es wird gefragt, ob man mit der Sorge über das Verschwinden des GIL in Python allein ist

    • Komplexem Multithreading-Code in beliebigen Sprachen sei schwer zu vertrauen, und bei Python sei das wegen seiner dynamischen Natur besonders beunruhigend

    • Man sei mit der Angst vor der Veränderung nicht allein, auch wenn die Begründung irrational sein könne

      • Der GIL sei reine technische Schuld und müsse zum Nutzen der Community entfernt werden
      • Heute würden in Python meist Non-Blocking I/O und async statt Threads verwendet
      • Wer keine Threads nutzt, erlebt durch den Wegfall des GIL keine Veränderung; auch C-Bibliotheken sind im Single-Thread-Fall sicher
      • Vorsicht ist nur nötig, wenn tatsächlich Threads verwendet werden
      • Naiver Python-Thread-Code wurde bisher durch den GIL daran gehindert, wirklich parallel zu laufen, und verhielt sich daher wie Single-Thread-Code; künftig wird er etwas schneller, könnte aber auch mehr Bugs zeigen
      • Die Lösung sei, keine Threads zu verwenden oder sich bei ihrer Nutzung richtig einzuarbeiten
      • In Zukunft werde es wohl bessere Abstraktionen geben; Diskussionen in der Community über Structured Concurrency und Ähnliches seien zu erwarten
    • Man selbst nutzt asyncio aktiv

      • Damit lässt sich in Python angenehm nebenläufig, aber Single-Thread-basiert programmieren, ähnlich wie in Node.js
      • Für Web- und Netzwerkaufgaben wird dieser Ansatz empfohlen
    • Es wird erwartet, dass es wie im ML/AI-Bereich läuft: Experten bauen zuerst komplexe Bibliotheken und reichen sie dann an normale Nutzer weiter

      • Der GIL sei in Python inzwischen in vielen Fällen zu einem ernsthaften Flaschenhals geworden
      • Deshalb habe man Go gelernt; die Sprache biete saubere Thread-Unterstützung, liege in der Abstraktion unter Python, aber über C/C++
      • Das Compiler-Modell sei als Hintergrund fast ebenso wichtig wie das Threading selbst
    • Es könnte unnötige Angst schüren, aber es wird daran erinnert, dass LLMs mit Python-Code trainiert wurden, der von der jahrzehntelangen Existenz des GIL ausging

    • Ob der GIL vorhanden ist oder nicht, betrifft nur jene, die Multicore-Arbeit wollen

      • Wer sich bisher weder um Threading noch um Multiprocessing gekümmert hat, wird praktisch keine Veränderung bemerken
      • Race-Condition-Probleme treten unabhängig vom GIL auf
  • Jemand nutzt Python oft, ist aber kein Experte, und startet gelegentlich mit concurrent.futures mehrere einfache Funktionen gleichzeitig

    • Es wird gefragt, was solche Nutzer künftig ändern müssen

    • Threads sind nicht mehr an den GIL gebunden und werden insgesamt schneller

      • Wenn Locks für gemeinsam genutzte Objekte sauber behandelt wurden, besteht kein zusätzlicher Grund zur Sorge
  • Es werden Eindrücke aus 20 Jahren professioneller Python-Erfahrung geteilt

    • Echte Threads seien nur dann wirklich nötig, wenn Message Passing unvermeidbar ist

      • Das Python-Ökosystem habe bereits für all diese Situationen Workarounds bereitgestellt
      • Wegen der vielen Fallstricke bei der Handhabung mehrerer Threads, etwa Locks, könnte das künftig nur noch in bestimmten Bibliotheken oder Domänen nötig sein
      • Wenn man aus reinem Python möglichst viel Leistung herausholen will, kann man Bibliotheken auf Basis von Native Code nutzen, etwa Pypy oder numba
      • Die eigentliche Performance-Revolution in Python sei letztlich asynchrone Programmierung; man solle sie unbedingt lernen
    • Jemand mit ähnlich langer Python-Erfahrung stimmt zu, formuliert es aber etwas anders

      • Python-Threads seien so schlecht gewesen, dass sich viele verschiedene Ausweichstrategien entwickelt hätten, um sie zu vermeiden
      • Wer CPU-bound Workloads per Threading doppelt so schnell machen wollte, stieß auf das GIL und wechselte dann zu Multiprocessing; dabei entstanden Kosten durch die Serialisierung von Datenstrukturen, was zu ineffizienten Ergebnissen wie 1,5-facher Geschwindigkeit bei doppelten Kernen führte
      • Es gebe viele Umgebungen, in denen gute Thread-Unterstützung nützlich wäre; weil es sie bisher nicht gab, habe man zu allerlei Ersatzansätzen gegriffen
      • Wenn es zur Situation passt, wird async ausdrücklich empfohlen (Glyph, du hattest recht!)
  • Es wird angemerkt, dass das Bild zwar KI-generiert sei, aber merkwürdigerweise eine Schlange mit zwei Schwänzen zeige

    • Eine scherzhafte Zustimmung empfiehlt, das stillschweigend zu übergehen; wenn in einem Python-Artikel eine Schlangenillustration auftaucht, sei das meist ohnehin ein Zeichen, dem man spielerisch keine große Aufmerksamkeit schenken müsse

    • Als Witz wird der Name „Confusoborus“ vorgeschlagen

  • Es wird darauf hingewiesen, dass die Schlange im Header-Bild zwei Schwänze zu haben scheint

    • Als Scherz heißt es, das sehe wohl aus, als wäre im selben Prozess ein zweiter Thread erzeugt worden
  • Es wird gefragt, ob es abgesehen von der Bibliotheksunterstützung weitere Einschränkungen gibt, WSGI und Celery-Worker in einem einzelnen Prozess zu betreiben

    • Es gebe keine Einschränkung, allerdings sei so ein Ansatz keine erstklassige Funktion der Sprache
      • Der GIL werde als Thema technischer Schuld beschrieben
      • Es gebe neben Parallelität noch weitere Gründe, warum die Aufhebung des GIL nötig sei
  • Es wird als enorme Grundlagenarbeit für das kommende Performance-Zeitalter betrachtet