Heim > Backend-Entwicklung > Python-Tutorial > Python Das Tor zu Hochleistungs-Multithreading ohne GIL

Python Das Tor zu Hochleistungs-Multithreading ohne GIL

Mary-Kate Olsen
Freigeben: 2025-01-06 16:58:41
Original
657 Leute haben es durchsucht

Einführung

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.

Was ist Global Interpreter Lock (GIL)?

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.

Warum die GIL ein Flaschenhals für Multithreading ist

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.

Python 3.13: Multithreading mit deaktivierter GIL freischalten

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.

Voraussetzungen für die Verwendung von Python 3.13 ohne GIL

  • Python 3.13-Quellcode: Das Deaktivieren der GIL ist in standardmäßigen vorgefertigten Binärdateien nicht verfügbar. Sie müssen Python 3.13 aus der Quelle mit dem Flag --disable-gil erstellen.
  • Multi-Core-CPU: Sie benötigen eine Multi-Core-CPU, um von echtem Multithreading zu profitieren, da Threads jetzt parallel über mehrere Kerne laufen.

Kompilieren von Python 3.13 mit deaktivierter GIL

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

Schritt für Schritt

  • Laden Sie den Python 3.13-Quellcode herunter Sie müssen zunächst den Python 3.13-Quellcode-Tarball von der offiziellen Python-Website herunterladen. Dies liegt daran, dass die vorgefertigten Binärdateien (wie diejenigen, die Sie direkt von python.org herunterladen) nicht mit Unterstützung für die Deaktivierung der GIL kompiliert sind. Sie können es über den Webbrowser oder mit wget oder sogar mit curl in Ihrem Terminal herunterladen
wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tgz
Nach dem Login kopieren
  • Extrahieren Sie die Quelle:
tar -xf Python-3.13.0.tgz
cd Python-3.13.0
Nach dem Login kopieren
  • Konfigurieren Sie den Build mit --disable-gil Sie müssen Python mit --disable-gil konfigurieren, um die Option zum Deaktivieren der GIL zu unterstützen.
./configure --disable-gil
Nach dem Login kopieren
  • Python kompilieren und installieren:
make
sudo make altinstall 
Nach dem Login kopieren
  • Wenn der Schritt „altinstall“ fehlschlägt, führen Sie den Befehl „configure“ mit dem Präfix „--prefix“ erneut aus
./configure --disable-gil --prefix=$HOME/python3.13
Nach dem Login kopieren
  • Führen Sie make altinstall im angegebenen Verzeichnis aus Führen Sie dann den Befehl make altinstall aus
make altinstall
Nach dem Login kopieren

So erkennen Sie GIL in Python 3.13

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()
Nach dem Login kopieren

Hands-On: Python-Multithreading mit GIL vs. GIL-Free

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()

Nach dem Login kopieren

Analyse:

## 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.
Nach dem Login kopieren

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.

Python The Gateway to High-Performance Multithreading Without GIL

Python The Gateway to High-Performance Multithreading Without GIL

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.

Wichtige Überlegungen vor der Deaktivierung der GIL

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.

GitHub-Repository

Den vollständigen Quellcode für die Beispiele in diesem Blog finden Sie auf meinem GitHub:

Python GIL-Leistungsanalyse

Haftungsausschluss:

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!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage