Python ist seit langem für seine Benutzerfreundlichkeit und Vielseitigkeit bekannt, aber ein Thema, das in der Python-Community viele Diskussionen ausgelöst hat, ist der Global Interpreter Lock (GIL). Die GIL war sowohl ein Schutz als auch ein Engpass für das Parallelitätsmodell von Python, insbesondere für CPU-gebundene Aufgaben, die andernfalls mehrere CPU-Kerne nutzen könnten. Mit der Veröffentlichung von Python 3.13 steht Python-Entwicklern jedoch eine bahnbrechende neue Option zur Verfügung: die Möglichkeit, die GIL zu deaktivieren. In diesem Blog wird untersucht, was die GIL ist, warum sie ein Hindernis für die Leistung beim Multithreading darstellt und wie man die GIL in Python 3.13 erkennt und deaktiviert, um echte Multithreading-Leistung freizuschalten.
Global Interpreter Lock (GIL) ist ein Mutex, der den Zugriff auf Python-Objekte schützt und verhindert, dass mehrere native Threads Python-Bytecode gleichzeitig ausführen. Dies gewährleistet Thread-Sicherheit für Python-Programme, allerdings auf Kosten der gleichzeitigen Ausführung. Die GIL macht Python-Threads für I/O-gebundene Aufgaben effizienter, schränkt jedoch ihre Leistung für CPU-gebundene Aufgaben ein.
Pythons GIL ermöglicht die gleichzeitige Ausführung nur eines Threads, selbst in Multithread-Programmen. Während dies für I/O-gebundene Aufgaben, bei denen das Programm auf Eingabe-/Ausgabevorgänge wartet, in Ordnung ist, schränkt es die Leistung für CPU-gebundene Aufgaben wie Zahlenverarbeitung, Datenanalyse oder Bildverarbeitung erheblich ein.
Mit Python 3.13 haben Entwickler die Möglichkeit, die GIL während des Python-Build-Prozesses zu deaktivieren. Das Deaktivieren der GIL ist jedoch in vorgefertigten Python-Distributionen nicht verfügbar. Stattdessen müssen Sie Python 3.13 aus dem Quellcode mit der Option --disable-gil kompilieren.
Diese neue Option öffnet die Tür für echte Parallelität bei CPU-gebundenen Multithread-Aufgaben und ermöglicht die parallele Ausführung von Threads über mehrere Kerne hinweg.
Um die GIL mit dem Flag -X gil=0 zu deaktivieren, müssen Sie Python aus dem Quellcode mit aktiviertem Flag --disable-gil kompilieren. Hier erfahren Sie, wie das geht
wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tgz
tar -xf Python-3.13.0.tgz cd Python-3.13.0
./configure --disable-gil
make sudo make altinstall
./configure --disable-gil --prefix=$HOME/python3.13
make altinstall
In Python 3.13 können Sie mit der Funktion sys._is_gil_enabled() überprüfen, ob die GIL aktiviert oder deaktiviert ist.
import sys def check_gil_status(): if sys.version_info >= (3, 13): status = sys._is_gil_enabled() if status: print("GIL is currently enabled.") else: print("GIL is currently disabled.") else: print("Python version does not support GIL status detection.") check_gil_status()
Der folgende Python-Code wurde entwickelt, um die Leistungssteigerungen beim Deaktivieren der GIL in Python 3.13 zu bewerten. Das Skript führt gleichzeitig acht Threads aus, von denen jeder die Aufgabe hat, die Primfaktoren großer Zahlen zu berechnen. Durch die Nutzung echter Parallelität hebt der Code die verbesserte Leistung hervor, die ohne die GIL erreicht wird.
#!/usr/bin/env python3 import sys import sysconfig import time from threading import Thread from multiprocessing import Process # Decorator to measure execution time of functions def calculate_execution_time(func): def wrapper(*args, **kwargs): start_time = time.perf_counter() result = func(*args, **kwargs) end_time = time.perf_counter() execution_time = end_time - start_time print(f"{func.__name__} took {execution_time:.4f} seconds.") return result return wrapper # Compute-intensive task: Iterative Fibonacci calculation def compute_fibonacci(n): """Compute Fibonacci number for a given n iteratively.""" a, b = 0, 1 for _ in range(n): a, b = b, a + b return a # Single-threaded task execution @calculate_execution_time def run_single_threaded(nums): for num in nums: compute_fibonacci(num) # Multi-threaded task execution @calculate_execution_time def run_multi_threaded(nums): threads = [Thread(target=compute_fibonacci, args=(num,)) for num in nums] for thread in threads: thread.start() for thread in threads: thread.join() # Multi-processing task execution @calculate_execution_time def run_multi_processing(nums): processes = [Process(target=compute_fibonacci, args=(num,)) for num in nums] for process in processes: process.start() for process in processes: process.join() # Main execution function def main(): # Check Python version and GIL status for Python 3.13+ print(f"Python Version: {sys.version}") py_version = float(".".join(sys.version.split()[0].split(".")[:2])) status = sysconfig.get_config_var("Py_GIL_DISABLED") if py_version >= 3.13: status = sys._is_gil_enabled() if status is None: print("GIL cannot be disabled for Python <= 3.12") elif status == 0: print("GIL is currently disabled") elif status == 1: print("GIL is currently active") # Run tasks on the same input size for comparison nums = [300000] * 8 print("\nRunning Single-Threaded Task:") run_single_threaded(nums) print("\nRunning Multi-Threaded Task:") run_multi_threaded(nums) print("\nRunning Multi-Processing Task:") run_multi_processing(nums) if __name__ == "__main__": main()
## Python 3.13 with GIL Disabled Python Version: 3.13.0 experimental free-threading build (main, Oct 14 2024, 17:09:28) [Clang 14.0.0 (clang-1400.0.29.202)] GIL is currently disabled Running Single-Threaded Task: run_single_threaded took 8.6587 seconds. Running Multi-Threaded Task: run_multi_threaded took 1.3885 seconds. Running Multi-Processing Task: run_multi_processing took 1.5953 seconds. ## Python 3.13 with GIL Enabled Python Version: 3.13.0 experimental free-threading build (main, Oct 14 2024, 17:09:28) [Clang 14.0.0 (clang-1400.0.29.202)] GIL is currently active Running Single-Threaded Task: run_single_threaded took 8.7108 seconds. Running Multi-Threaded Task: run_multi_threaded took 8.6645 seconds. Running Multi-Processing Task: run_multi_processing took 1.4530 seconds. ## Python 3.12 Python Version: 3.12.6 (main, Sep 7 2024, 19:30:10) [Clang 14.0.0 (clang-1400.0.29.202)] GIL cannot be disabled for Python <= 3.12 Running Single-Threaded Task: run_single_threaded took 8.7004 seconds. Running Multi-Threaded Task: run_multi_threaded took 8.6297 seconds. Running Multi-Processing Task: run_multi_processing took 1.4876 seconds.
Multithread-Leistung:Der wahre Vorteil der Deaktivierung der GIL zeigt sich im Multithread-Szenario:
Bei deaktivierter GIL (3.13) beträgt die Ausführungszeit 1,5703 Sekunden.
Bei aktivierter GIL (3.13) beträgt die Ausführungszeit 8,5901 Sekunden.
Ergebnis: Das Deaktivieren der GIL führte zu einer Leistungsverbesserung von etwa 81,7 % für Multithread-Aufgaben.
Das Diagramm zeigt deutlich, dass die Deaktivierung der GIL in Python 3.13 zu einer erheblichen Leistungssteigerung für CPU-gebundene Multithread-Aufgaben führt, sodass Python mehrere CPU-Kerne parallel effizient nutzen kann. Während die Single-Thread- und Multi-Processing-Leistung weitgehend unberührt bleibt, zeigt die Multi-Thread-Leistung eine deutliche Verbesserung, was Python 3.13 zu einem Game-Changer für CPU-intensive Anwendungen macht, die auf Multi-Threading angewiesen sind.
Python-Versionen vor 3.13 unterstützen jedoch nicht die Deaktivierung der GIL, was erklärt, warum ihre Multithread-Leistung der von Python 3.13 mit aktivierter GIL ähnlich bleibt. Diese Einschränkung in früheren Versionen schränkt weiterhin die Fähigkeit von Python ein, Multithreading für CPU-gebundene Aufgaben vollständig zu nutzen.
Das Deaktivieren der Global Interpreter Lock (GIL) in Python 3.13 kann erhebliche Leistungsverbesserungen bei CPU-gebundenen Multithread-Aufgaben ermöglichen. Bevor Sie dies tun, müssen Sie jedoch einige wichtige Faktoren berücksichtigen:
Thread-Sicherheit:Ohne die GIL müssen Sie die Thread-Sicherheit mithilfe von Sperren oder anderen Synchronisierungsmechanismen manuell handhaben, um Race Conditions in Ihrem Code zu verhindern.
Potenzielle Leistungseinbußen: Feinkörniges Sperren kann zu Konflikten führen, die die Leistung bei Single-Thread- oder E/A-gebundenen Aufgaben beeinträchtigen können, die zuvor von der GIL profitiert haben.
Kompatibilität mit Bibliotheken von Drittanbietern: Viele C-Erweiterungen und Bibliotheken gehen aus Gründen der Thread-Sicherheit von der Anwesenheit der GIL aus. Das Deaktivieren der GIL erfordert möglicherweise Aktualisierungen dieser Bibliotheken, um sicherzustellen, dass sie in einer Multithread-Umgebung ordnungsgemäß funktionieren.
Komplexe Speicherverwaltung: Das Deaktivieren der GIL erhöht die Komplexität der Speicherverwaltung und erfordert eine threadsichere Speicherverwaltung, was das Risiko von Bugs und Fehlern erhöhen kann.
E/A-gebundene Aufgaben: Das Deaktivieren der GIL bietet begrenzte Vorteile für E/A-gebundene Aufgaben, bei denen nicht blockierende E/A-Mechanismen wie Asyncio möglicherweise effektiver sind.
Schwierigkeiten beim Debuggen: Ohne die GIL kann das Debuggen von Multithread-Anwendungen aufgrund der erhöhten Wahrscheinlichkeit von Race Conditions und Deadlocks schwieriger werden.
Höhere Speichernutzung: Die Verwendung von Sperren und die Verwaltung von Thread-Status ohne die GIL kann den Speicherverbrauch erhöhen, insbesondere in Multithread-Anwendungen.
Eingebettete Systeme: Das Deaktivieren der GIL könnte die Integration von Python in Multithread-Umgebungen in eingebetteten Systemen erschweren und mehr Aufwand für eine effektive Integration erfordern.
Sperrenkonflikt: In einigen Fällen kann das Deaktivieren der GIL zu Sperrenkonflikten zwischen Threads führen, was die erwarteten Leistungsverbesserungen verringern könnte.
Den vollständigen Quellcode für die Beispiele in diesem Blog finden Sie auf meinem GitHub:
Python GIL-Leistungsanalyse
Dies ist ein persönlicher Blog. Die hier geäußerten Ansichten und Meinungen sind ausschließlich die des Autors und stellen nicht die einer Organisation oder Einzelperson dar, mit der der Autor beruflich oder persönlich in Verbindung steht.
Das obige ist der detaillierte Inhalt vonPython Das Tor zu Hochleistungs-Multithreading ohne GIL. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!