Lesedauer 6 Minuten

Jahrelang hieß parallele Verarbeitung in Python vor allem eins: Kompromisse. Threads helfen bei I/O, aber nicht bei Rechenlast. Prozesse helfen bei Rechenlast, kosten aber Speicher und Startzeit. Mit Python 3.14 verschiebt sich dieses Bild deutlich. Der Free-threaded Build ohne GIL ist jetzt offiziell unterstützt, Subinterpreter sind in der Standardbibliothek angekommen, und auch multiprocessing, concurrent.futures und asyncio haben nützliche Neuerungen bekommen.

In diesem Beitrag bekommst du einen Überblick über alle Wege, mit denen du in Python 3.14 parallel oder nebenläufig arbeiten kannst, samt Codebeispielen und einer Entscheidungshilfe, welcher Ansatz zu deinem Problem passt.

Das Grundproblem: der Global Interpreter Lock (GIL)

Der GIL ist eine Sperre im Standard-Interpreter CPython. Er sorgt dafür, dass immer nur ein Thread gleichzeitig Python-Bytecode ausführt. Das macht die interne Speicherverwaltung einfach und schnell, hat aber eine unangenehme Folge: Startest du vier Threads für eine rechenintensive Aufgabe, laufen sie nicht wirklich parallel, sondern wechseln sich ab. Auf einem Rechner mit acht Kernen nutzt du so praktisch nur einen.

Bei I/O-lastigen Aufgaben (Netzwerkanfragen, Dateizugriffe, Datenbankabfragen) ist das weniger schlimm, weil Threads den GIL freigeben, während sie warten. Bei reiner Rechenarbeit war der GIL aber bisher der Flaschenhals schlechthin.

Threads mit GIL im Vergleich zum Free-threaded Build

Die Möglichkeiten in Python 3.14 im Überblick

Python 3.14 bietet dir vier grundlegende Werkzeuge. Sie lösen unterschiedliche Probleme, und oft ist die Wahl zwischen ihnen wichtiger als jede Mikro-Optimierung.

Vier Wege zur parallelen Verarbeitung in Python 3.14

1. Free-threaded Python: Threads ohne GIL

Die größte Neuerung für parallele Verarbeitung in Python 3.14 ist der Status des Free-threaded Builds. In Python 3.13 war er noch experimentell. Mit PEP 779 ist er in 3.14 offiziell unterstützt. Das bedeutet: Er ist kein Spielzeug mehr, sondern eine echte Option für produktiven Code. Der Standard-Build mit GIL bleibt aber weiterhin die Voreinstellung.

So installierst du den Free-threaded Build

Der Free-threaded Build ist eine eigene Variante des Interpreters, erkennbar am t im Namen, also python3.14t. Du bekommst ihn zum Beispiel so:

  • Offizielle Installer für Windows und macOS: Dort kannst du die Free-threaded-Variante als optionale Komponente mitinstallieren.
  • uv: uv python install 3.14t
  • pyenv: pyenv install 3.14t
  • Docker oder Linux-Distributionen: viele bieten eigene Pakete wie python3.14-nogil oder ähnlich an.

Ob der GIL in deiner laufenden Sitzung aktiv ist, prüfst du so:

Ein Beispiel mit echter Parallelität

Der Clou: Du musst deinen Code nicht umschreiben. Derselbe ThreadPoolExecutor, der im normalen Build kaum schneller ist als eine einfache Schleife, nutzt unter python3.14t alle Kerne.

Führe das Skript einmal mit python3.14 und einmal mit python3.14t aus. Auf einem Rechner mit mindestens vier Kernen siehst du im Free-threaded Build eine deutliche Beschleunigung, oft nahe am Faktor vier.

Worauf du achten musst

  • Single-Thread-Overhead: Der Free-threaded Build ist bei rein sequenziellem Code etwas langsamer als der Standard-Build. In 3.14 ist dieser Nachteil gegenüber 3.13 deutlich geschrumpft und liegt grob im einstelligen Prozentbereich, je nach Plattform und Workload.
  • C-Erweiterungen: Erweiterungsmodule müssen ausdrücklich erklären, dass sie ohne GIL sicher sind. Importierst du ein Modul, das das nicht tut, aktiviert Python den GIL automatisch wieder und gibt eine Warnung aus. Mit PYTHON_GIL=0 oder -X gil=0 kannst du das erzwingen, aber nur, wenn du weißt, was du tust.
  • Race Conditions: Ohne GIL laufen deine Threads wirklich gleichzeitig. Gemeinsam genutzte veränderliche Daten schützt du mit threading.Lock oder nutzt thread-sichere Strukturen wie queue.Queue.

2. Subinterpreter: Parallelität im selben Prozess

Die zweite große Neuerung ist PEP 734: Mehrere Interpreter sind jetzt über das neue Modul concurrent.interpreters direkt aus Python nutzbar. Jeder Subinterpreter hat seinen eigenen Zustand und seinen eigenen GIL. Dadurch laufen sie auch im normalen Build mit GIL echt parallel.

Du kannst dir Subinterpreter als Mittelweg zwischen Threads und Prozessen vorstellen: Sie sind voneinander isoliert wie Prozesse, leben aber im selben Betriebssystemprozess und starten schneller.

Der einfache Weg: InterpreterPoolExecutor

Am bequemsten nutzt du Subinterpreter über den neuen InterpreterPoolExecutor. Er hat dieselbe Schnittstelle wie ThreadPoolExecutor und ProcessPoolExecutor:

Die Funktion liegt hier bewusst in einem eigenen Modul. Funktionen und Argumente werden an die Subinterpreter übergeben und müssen dort importierbar beziehungsweise serialisierbar sein. Funktionen aus dem Hauptskript machen dabei schnell Probleme.

Mehr Kontrolle mit concurrent.interpreters

Wenn du direkt mit Interpretern arbeiten willst, bietet dir das Low-Level-Modul mehr Kontrolle:

Einschränkung: Nicht jedes C-Erweiterungsmodul unterstützt bereits mehrere Interpreter. Bei reinem Python-Code und der Standardbibliothek bist du auf der sicheren Seite, bei großen Bibliotheken mit C-Code solltest du vorher testen.

3. Multiprocessing: der bewährte Klassiker

Das Modul multiprocessing und der ProcessPoolExecutor starten separate Prozesse mit jeweils eigenem Interpreter. Das umgeht den GIL vollständig und funktioniert mit praktisch jeder Bibliothek. Der Preis: Jeder Prozess braucht eigenen Speicher, und Daten zwischen Prozessen müssen serialisiert werden.

Was sich in Python 3.14 ändert

  • Neue Standard-Startmethode: Unter Linux und anderen POSIX-Systemen (außer macOS) ist die Voreinstellung jetzt forkserver statt fork. Das ist sicherer, vor allem in Programmen, die zusätzlich Threads nutzen. macOS und Windows verwenden weiterhin spawn. Wenn dein Code bisher stillschweigend auf geerbten globalen Zustand vertraut hat, kann er dadurch brechen. Brauchst du das alte Verhalten, setzt du es explizit mit multiprocessing.set_start_method("fork") oder übergibst einen passenden mp_context.
  • Worker gezielt beenden: ProcessPoolExecutor hat die neuen Methoden terminate_workers() und kill_workers(). Damit beendest du hängende Worker, ohne auf ihr Ende warten zu müssen.
  • Speicherschonendes map(): Executor.map() kennt den neuen Parameter buffersize. Er begrenzt, wie viele Aufgaben gleichzeitig vorgemerkt werden. Das ist praktisch, wenn du sehr große oder unendliche Eingaben verarbeitest.

4. asyncio: Nebenläufigkeit für I/O

asyncio ist streng genommen keine parallele Verarbeitung, sondern Nebenläufigkeit: Ein einzelner Thread wechselt zwischen vielen Aufgaben, immer dann, wenn eine davon wartet. Für Webserver, Crawler oder Anwendungen mit tausenden gleichzeitigen Verbindungen ist das oft die effizienteste Lösung.

Hundert Anfragen à eine Sekunde dauern hier insgesamt rund eine Sekunde, nicht hundert.

Neu in 3.14: laufende Tasks untersuchen

Python 3.14 bringt eine praktische Debugging-Hilfe mit. Du kannst von außen in einen laufenden Prozess schauen und siehst, welche Tasks gerade existieren und worauf sie warten:

Die Zahl ist die Prozess-ID deines Programms. Gerade bei hängenden Anwendungen sparst du dir damit viel Rätselraten. Innerhalb des Programms liefert asyncio.capture_call_graph() ähnliche Informationen.

Welcher Ansatz passt zu dir?

Die wichtigste Frage lautet: Wartet dein Programm vor allem auf etwas (I/O), oder rechnet es (CPU)? Danach entscheidet die Kompatibilität deiner Bibliotheken.

Entscheidungshilfe für parallele Verarbeitung in Python 3.14

Praxistipps für den Umstieg

  • Erst messen, dann parallelisieren. Mit cProfile oder time.perf_counter() findest du heraus, wo dein Programm wirklich Zeit verliert.
  • Setze auf concurrent.futures. Da ThreadPoolExecutor, InterpreterPoolExecutor und ProcessPoolExecutor dieselbe Schnittstelle haben, kannst du die Varianten mit einer einzigen geänderten Zeile vergleichen.
  • Teste den Free-threaded Build parallel. Lass deine Testsuite in CI zusätzlich unter python3.14t laufen. So siehst du früh, ob deine Abhängigkeiten mitspielen.
  • Prüfe deine Startmethode. Nach dem Upgrade auf 3.14 unter Linux lohnt sich ein Blick auf Code, der mit multiprocessing arbeitet und sich auf fork verlassen hat.
  • Kombiniere Ansätze. Ein asyncio-Webserver kann rechenintensive Teile mit loop.run_in_executor() an einen Prozess- oder Interpreter-Pool auslagern.

Fazit

Python 3.14 ist ein Wendepunkt für parallele Verarbeitung. Mit dem offiziell unterstützten Free-threaded Build kannst du Threads endlich auch für Rechenlast nutzen. Subinterpreter bieten dir echte Parallelität ohne den Overhead separater Prozesse. Und die bewährten Werkzeuge multiprocessing und asyncio sind durch sinnvolle Detailverbesserungen robuster und besser zu debuggen geworden. Noch ist der GIL-freie Betrieb nicht die Voreinstellung und das Ökosystem zieht schrittweise nach. Jetzt ist aber ein guter Zeitpunkt, deine Projekte darauf vorzubereiten.

Alle Details zu den Neuerungen findest du in der offiziellen Übersicht What’s New in Python 3.14 und in der Anleitung Python support for free threading.

Häufige Fragen zu Python 3.14 und paralleler Verarbeitung

Ist der GIL in Python 3.14 abgeschafft?

Nein. Der Standard-Build von Python 3.14 hat weiterhin einen GIL. Es gibt aber zusätzlich den offiziell unterstützten Free-threaded Build (python3.14t), der ohne GIL läuft. Du entscheidest selbst, welchen Interpreter du verwendest.

Ist der Free-threaded Build schon produktionsreif?

Er ist offiziell unterstützt und damit für den produktiven Einsatz gedacht. Ob er für dein Projekt passt, hängt vor allem davon ab, ob alle genutzten C-Erweiterungen free-threading-fähig sind. Teste deine Anwendung gründlich, bevor du umstellst.

Was ist der Unterschied zwischen Subinterpretern und Threads?

Threads teilen sich den gesamten Speicher und alle Objekte. Subinterpreter sind voneinander isoliert und tauschen Daten nur über definierte Kanäle wie Queues aus. Dadurch gibt es weniger Race Conditions, aber auch mehr Aufwand beim Datenaustausch.

Brauche ich multiprocessing überhaupt noch?

Ja. Multiprocessing ist die robusteste Lösung, wenn du Bibliotheken nutzt, die weder Free-threading noch Subinterpreter unterstützen, oder wenn du maximale Isolation willst. Stürzt ein Prozess ab, bleiben die anderen davon unberührt.

Wird mein bestehender Code mit Python 3.14 schneller?

Nicht automatisch. Mit dem Standard-Build ändert sich an der Parallelität deiner Threads nichts. Nutzt du bereits ThreadPoolExecutor für Rechenlast, kann der Wechsel auf python3.14t ohne Codeänderung einen deutlichen Geschwindigkeitsgewinn bringen.

Ist asyncio parallel?

Nein, asyncio ist nebenläufig. Alle Tasks laufen in einem Thread und wechseln sich an await-Stellen ab. Für I/O-lastige Aufgaben ist das sehr effizient, für Rechenlast brauchst du Threads, Subinterpreter oder Prozesse.