Multithreading in Python mit Beispiel: Lernen Sie GIL in Python

Die Programmiersprache Python ermöglicht Ihnen die Verwendung von Multiprocessing oder Multithreading. In diesem Tutorial lernen Sie, wie Sie Multithread-Anwendungen in Python.

Was ist ein Faden?

Ein Thread ist eine Ausführungseinheit für die gleichzeitige Programmierung. Multithreading ist eine Technik, die es einer CPU ermöglicht, viele Aufgaben eines Prozesses gleichzeitig auszuführen. Diese Threads können einzeln ausgeführt werden, während sie ihre Prozessressourcen gemeinsam nutzen.

Was ist ein Prozess?

Ein Prozess ist im Grunde das ausgeführte Programm. Wenn Sie eine Anwendung auf Ihrem Computer starten (z. B. einen Browser oder einen Texteditor), erstellt das Betriebssystem einen

Was ist Multithreading in Python?

Multithreading in Python Programmierung ist eine bekannte Technik, bei der mehrere Threads in einem Prozess ihren Datenraum mit dem Haupt-Thread teilen, was den Informationsaustausch und die Kommunikation innerhalb von Threads einfach und effizient macht. Threads sind leichter als Prozesse. Mehrere Threads können einzeln ausgeführt werden, während sie ihre Prozessressourcen gemeinsam nutzen. Der Zweck von Multithreading besteht darin, mehrere Aufgaben und Funktionszellen gleichzeitig auszuführen.

Was ist Multiprocessing?

Multiprozessing ermöglicht Ihnen, mehrere unabhängige Prozesse gleichzeitig auszuführen. Diese Prozesse teilen ihre Ressourcen nicht und kommunizieren über IPC.

Python Multithreading vs. Multiprocessing

Um Prozesse und Threads zu verstehen, stellen Sie sich dieses Szenario vor: Eine .exe-Datei auf Ihrem Computer ist ein Programm. Wenn Sie es öffnen, lädt das Betriebssystem es in den Speicher und die CPU führt es aus. Die Instanz des Programms, die gerade ausgeführt wird, wird als Prozess bezeichnet.

Jeder Prozess besteht aus zwei grundlegenden Komponenten:

  • Der Code des Chamäleons
  • Die Fakten

Nun kann ein Prozess einen oder mehrere aufgerufene Unterteile enthalten Threads. Dies hängt von der Betriebssystemarchitektur ab. Sie können sich einen Thread als einen Abschnitt des Prozesses vorstellen, der vom Betriebssystem separat ausgeführt werden kann.

Mit anderen Worten handelt es sich um einen Befehlsstrom, der vom Betriebssystem unabhängig ausgeführt werden kann. Threads innerhalb eines einzelnen Prozesses teilen die Daten dieses Prozesses und sind so konzipiert, dass sie zusammenarbeiten, um Parallelität zu ermöglichen.

Warum Multithreading verwenden?

Mit Multithreading können Sie eine Anwendung in mehrere Unteraufgaben aufteilen und diese Aufgaben gleichzeitig ausführen. Wenn Sie Multithreading richtig verwenden, können Sie die Geschwindigkeit, Leistung und Darstellung Ihrer Anwendung verbessern.

Python Multithreading

Python unterstützt Konstrukte sowohl für Multiprocessing als auch für Multithreading. In diesem Tutorial konzentrieren Sie sich hauptsächlich auf die Implementierung Multithreading Anwendungen mit Python. Es gibt zwei Hauptmodule, die zum Verarbeiten von Threads in Python:

  1. Das Faden Modul und
  2. Das einfädeln Modulen

In Python gibt es jedoch auch eine sogenannte globale Interpretersperre (GIL). Es ermöglicht keinen großen Leistungszuwachs, vielleicht sogar Veteran die Leistung einiger Multithread-Anwendungen. Alles darüber erfahren Sie in den nächsten Abschnitten dieses Tutorials.

Die Thread- und Threading-Module

Die beiden Module, die Sie in diesem Tutorial kennenlernen werden, sind: Thread-Modul und den Threading-Modul.

Das Thread-Modul ist jedoch schon lange veraltet. Beginnend mit Python 3, es wurde als veraltet gekennzeichnet und ist nur zugänglich als __Gewinde für Abwärtskompatibilität.

Sie sollten die höhere Ebene verwenden einfädeln Modul für Anwendungen, die Sie bereitstellen möchten. Das Thread-Modul wurde hier nur zu Bildungszwecken behandelt.

Das Thread-Modul

Die Syntax zum Erstellen eines neuen Threads mit diesem Modul lautet wie folgt:

thread.start_new_thread(function_name, arguments)

Okay, jetzt haben Sie die grundlegende Theorie behandelt, um mit dem Codieren zu beginnen. Also, öffnen Sie Ihr IDLE oder einen Notizblock und geben Sie Folgendes ein:

import time
import _thread

def thread_test(name, wait):
   i = 0
   while i <= 3:
      time.sleep(wait)
      print("Running %s\n" %name)
      i = i + 1

   print("%s has finished execution" %name)

if __name__ == "__main__":
    
    _thread.start_new_thread(thread_test, ("First Thread", 1))
    _thread.start_new_thread(thread_test, ("Second Thread", 2))
    _thread.start_new_thread(thread_test, ("Third Thread", 3))

Speichern Sie die Datei und drücken Sie F5, um das Programm auszuführen. Wenn alles richtig gemacht wurde, sollten Sie folgende Ausgabe sehen:

Das Thread-Modul

In den nächsten Abschnitten erfahren Sie mehr über die Rennbedingungen und deren Handhabung

Das Thread-Modul

CODE-ERKLÄRUNG

  1. Diese Anweisungen importieren das Zeit- und Threadmodul, das für die Ausführung und Verzögerung des Python Threads.
  2. Hier haben Sie eine Funktion namens definiert thread_test, welches von der aufgerufen wird start_new_thread Methode. Die Funktion führt vier Iterationen lang eine While-Schleife aus und gibt den Namen des Threads aus, der sie aufgerufen hat. Sobald die Iteration abgeschlossen ist, wird eine Meldung ausgegeben, die besagt, dass die Ausführung des Threads abgeschlossen ist.
  3. Dies ist der Hauptabschnitt Ihres Programms. Hier rufen Sie einfach die an start_new_thread Methode mit der thread_test Funktion als Argument. Dadurch wird ein neuer Thread für die Funktion, die Sie als Argument übergeben, erstellt und mit der Ausführung begonnen. Beachten Sie, dass Sie dies ersetzen können (Thread_test) mit einer anderen Funktion, die Sie als Thread ausführen möchten.

Das Threading-Modul

Dieses Modul ist die High-Level-Implementierung von Threading in Python und der De-facto-Standard für die Verwaltung von Multithread-Anwendungen. Im Vergleich zum Thread-Modul bietet es eine Vielzahl von Funktionen.

Struktur des Threading-Moduls
Struktur des Threading-Moduls

Hier ist eine Liste einiger nützlicher Funktionen, die in diesem Modul definiert sind:

Funktionsname Beschreibung
activeCount() Gibt die Anzahl von zurück Thread Objekte, die noch am Leben sind
aktuellerThread() Gibt das aktuelle Objekt der Thread-Klasse zurück.
aufzählen() Listet alle aktiven Thread-Objekte auf.
isDaemon() Gibt true zurück, wenn der Thread ein Daemon ist.
ist am Leben() Gibt true zurück, wenn der Thread noch aktiv ist.
Methoden der Thread-Klasse
Start() Startet die Aktivität eines Threads. Es darf für jeden Thread nur einmal aufgerufen werden, da es bei mehrmaligem Aufruf einen Laufzeitfehler auslöst.
Lauf() Diese Methode bezeichnet die Aktivität eines Threads und kann von einer Klasse überschrieben werden, die die Thread-Klasse erweitert.
beitreten() Es blockiert die Ausführung anderen Codes, bis der Thread, für den die Methode join() aufgerufen wurde, beendet wird.

Hintergrundgeschichte: Die Thread-Klasse

Bevor Sie mit der Codierung von Multithread-Programmen unter Verwendung des Threading-Moduls beginnen, ist es wichtig, dass Sie die Thread-Klasse verstehen. Die Thread-Klasse ist die primäre Klasse, die die Vorlage und die Operationen eines Threads in Python definiert.

Die gebräuchlichste Methode zum Erstellen einer Multithread-Python-Anwendung besteht darin, eine Klasse zu deklarieren, die die Thread-Klasse erweitert und deren run()-Methode überschreibt.

Zusammenfassend stellt die Thread-Klasse eine Codesequenz dar, die separat ausgeführt wird Faden der Kontrolle.

Wenn Sie eine Multithread-App schreiben, gehen Sie also wie folgt vor:

  1. Definieren Sie eine Klasse, die die Thread-Klasse erweitert
  2. Überschreiben Sie die __init__ Konstruktor
  3. Überschreiben Sie die Lauf() Methode

Sobald ein Thread-Objekt erstellt wurde, wird das Start() Mit der Methode kann mit der Ausführung dieser Aktivität begonnen werden beitreten() Die Methode kann verwendet werden, um den gesamten anderen Code zu blockieren, bis die aktuelle Aktivität beendet ist.

Versuchen wir nun, das Threading-Modul zur Implementierung Ihres vorherigen Beispiels zu verwenden. Starten Sie noch einmal Ihr IDLE und geben Sie Folgendes ein:

import time
import threading

class threadtester (threading.Thread):
    def __init__(self, id, name, i):
       threading.Thread.__init__(self)
       self.id = id
       self.name = name
       self.i = i
       
    def run(self):
       thread_test(self.name, self.i, 5)
       print ("%s has finished execution " %self.name)

def thread_test(name, wait, i):

    while i:
       time.sleep(wait)
       print ("Running %s \n" %name)
       i = i - 1

if __name__=="__main__":
    thread1 = threadtester(1, "First Thread", 1)
    thread2 = threadtester(2, "Second Thread", 2)
    thread3 = threadtester(3, "Third Thread", 3)

    thread1.start()
    thread2.start()
    thread3.start()

    thread1.join()
    thread2.join()
    thread3.join()

Dies wird die Ausgabe sein, wenn Sie den obigen Code ausführen:

Hintergrundgeschichte: Die Thread-Klasse

CODE-ERKLÄRUNG

Hintergrundgeschichte: Die Thread-Klasse

  1. Dieser Teil ist derselbe wie in unserem vorherigen Beispiel. Hier importieren Sie das Zeit- und Thread-Modul, die für die Ausführung und Verzögerungen des Python Threads.
  2. In diesem Teil erstellen Sie eine Klasse namens Threadtester, die die Klasse erbt oder erweitert Thread Klasse des Threading-Moduls. Dies ist eine der gebräuchlichsten Methoden zum Erstellen von Threads in Python. Sie sollten jedoch nur den Konstruktor und die überschreiben Lauf() Methode in Ihrer App. Wie Sie im obigen Codebeispiel sehen können, ist die __init__ Methode (Konstruktor) wurde überschrieben. Ebenso haben Sie auch das überschrieben Lauf() Methode. Es enthält den Code, den Sie innerhalb eines Threads ausführen möchten. In diesem Beispiel haben Sie die Funktion thread_test() aufgerufen.
  3. Dies ist die Methode thread_test(), die den Wert von annimmt i als Argument, verringert es bei jeder Iteration um 1 und durchläuft den Rest des Codes, bis i 0 wird. In jeder Iteration gibt es den Namen des aktuell ausgeführten Threads aus und schläft für Wartesekunden (was auch als Argument verwendet wird). ).
  4. thread1 = threadtester(1, „First Thread“, 1) Hier erstellen wir einen Thread und übergeben die drei Parameter, die wir in __init__ deklariert haben. Der erste Parameter ist die ID des Threads, der zweite Parameter ist der Name des Threads und der dritte Parameter ist der Zähler, der bestimmt, wie oft die while-Schleife ausgeführt werden soll.
  5. thread2.start()D Die Startmethode wird verwendet, um die Ausführung eines Threads zu starten. Intern ruft die Funktion start() die Methode run() Ihrer Klasse auf.
  6. thread3.join() Die Methode join() blockiert die Ausführung anderen Codes und wartet, bis der Thread, in dem sie aufgerufen wurde, beendet ist.

Wie Sie bereits wissen, haben die Threads, die sich im selben Prozess befinden, Zugriff auf den Speicher und die Daten dieses Prozesses. Wenn daher mehrere Threads gleichzeitig versuchen, die Daten zu ändern oder darauf zuzugreifen, können sich Fehler einschleichen.

Im nächsten Abschnitt sehen Sie die verschiedenen Arten von Komplikationen, die auftreten können, wenn Threads auf Daten und kritische Abschnitte zugreifen, ohne nach vorhandenen Zugriffstransaktionen zu suchen.

Deadlocks und Race Conditions

Bevor wir uns mit Deadlocks und Race Conditions befassen, ist es hilfreich, einige grundlegende Definitionen im Zusammenhang mit paralleler Programmierung zu verstehen:

  • Kritischer Abschnitt: Dies ist ein Codefragment, das auf gemeinsam genutzte Variablen zugreift oder diese ändert und als atomare Transaktion ausgeführt werden muss.
  • Kontextwechsel: Dies ist der Vorgang, den eine CPU durchführt, um den Status eines Threads zu speichern, bevor von einer Aufgabe zu einer anderen gewechselt wird, sodass er später an derselben Stelle fortgesetzt werden kann.

Blockaden

Blockaden sind das am meisten gefürchtete Problem, mit dem Entwickler konfrontiert werden, wenn sie gleichzeitige/multithreaded Anwendungen in Python schreiben. Deadlocks lassen sich am besten anhand des klassischen Beispielproblems der Informatik verstehen, das als Restaurants PhiloSophers Problem.

Die Problemstellung für speisende Philosophen lautet wie folgt:

Fünf Philosophen sitzen an einem runden Tisch mit fünf Tellern Spaghetti (eine Nudelsorte) und fünf Gabeln, wie in der Abbildung dargestellt.

Restaurants PhiloSophers Problem

Restaurants PhiloSophers Problem

Ein Philosoph muss zu jeder Zeit entweder essen oder nachdenken.

Darüber hinaus muss ein Philosoph die beiden Gabeln neben ihm nehmen (also die linke und die rechte Gabel), bevor er die Spaghetti essen kann. Das Deadlock-Problem tritt auf, wenn alle fünf Philosophen gleichzeitig ihre rechte Gabel nehmen.

Da jeder der Philosophen eine Gabel hat, werden sie alle warten, bis die anderen ihre Gabeln hinlegen. Infolgedessen wird keiner von ihnen Spaghetti essen können.

Ähnlich verhält es sich in einem parallelen System: Ein Deadlock tritt auf, wenn verschiedene Threads oder Prozesse (Philosophen) gleichzeitig versuchen, die gemeinsam genutzten Systemressourcen (Forks) zu beanspruchen. Dies führt dazu, dass keiner der Prozesse ausgeführt werden kann, da sie auf eine andere Ressource warten, die von einem anderen Prozess gehalten wird.

Rennbedingungen

Ein Race Condition ist ein unerwünschter Zustand eines Programms, der auftritt, wenn ein System zwei oder mehr Operationen gleichzeitig ausführt. Betrachten Sie beispielsweise diese einfache for-Schleife:

i=0; # a global variable
for x in range(100):
    print(i)
    i+=1;

Wenn Sie erstellen n Anzahl der Threads, die diesen Code gleichzeitig ausführen, können Sie den Wert von i (der von den Threads gemeinsam genutzt wird) nicht bestimmen, wenn das Programm die Ausführung beendet. Dies liegt daran, dass sich die Threads in einer echten Multithreading-Umgebung überlappen können und sich der Wert von i, der von einem Thread abgerufen und geändert wurde, zwischendurch ändern kann, wenn ein anderer Thread darauf zugreift.

Dies sind die beiden Haupttypen von Problemen, die in einer Multithread- oder verteilten Python-Anwendung auftreten können. Im nächsten Abschnitt erfahren Sie, wie Sie dieses Problem durch die Synchronisierung von Threads lösen können.

Syncchronisierende Threads

Um mit Race Conditions, Deadlocks und anderen Thread-basierten Problemen umzugehen, bietet das Threading-Modul die Zahnscheiben Objekt. Die Idee ist, dass ein Thread, wenn er auf eine bestimmte Ressource zugreifen möchte, eine Sperre für diese Ressource erhält. Sobald ein Thread eine bestimmte Ressource sperrt, kann kein anderer Thread darauf zugreifen, bis die Sperre aufgehoben wird. Dadurch werden die Änderungen an der Ressource atomar und Race Conditions werden vermieden.

Eine Sperre ist ein Synchronisierungsprimitiv auf niedriger Ebene, das von der __Gewinde Modul. Eine Sperre kann sich jederzeit in einem von zwei Zuständen befinden: verschlossen or entsperrt. Es unterstützt zwei Methoden:

  1. erwerben()Wenn der Sperrzustand entsperrt ist, wird durch Aufrufen der Methode „acquire()“ der Zustand in „gesperrt“ geändert und zurückgegeben. Wenn der Status jedoch gesperrt ist, wird der Aufruf von acquire() blockiert, bis die Methode release() von einem anderen Thread aufgerufen wird.
  2. freigeben()Mit der Methode release() wird der Zustand auf „unlocked“ gesetzt, also eine Sperre aufgehoben. Es kann von jedem Thread aufgerufen werden, nicht unbedingt von dem Thread, der die Sperre erhalten hat.

Hier ist ein Beispiel für die Verwendung von Sperren in Ihren Apps. Starten Sie Ihr IDLE und geben Sie Folgendes ein:

import threading
lock = threading.Lock()

def first_function():
    for i in range(5):
        lock.acquire()
        print ('lock acquired')
        print ('Executing the first funcion')
        lock.release()

def second_function():
    for i in range(5):
        lock.acquire()
        print ('lock acquired')
        print ('Executing the second funcion')
        lock.release()

if __name__=="__main__":
    thread_one = threading.Thread(target=first_function)
    thread_two = threading.Thread(target=second_function)

    thread_one.start()
    thread_two.start()

    thread_one.join()
    thread_two.join()

Drücken Sie nun F5. Sie sollten eine Ausgabe wie diese sehen:

Syncchronisierende Threads

CODE-ERKLÄRUNG

Syncchronisierende Threads

  1. Hier erstellen Sie einfach eine neue Sperre, indem Sie die aufrufen threading.Lock() Werksfunktion. Intern gibt Lock() eine Instanz der effektivsten konkreten Lock-Klasse zurück, die von der Plattform verwaltet wird.
  2. In der ersten Anweisung erhalten Sie die Sperre, indem Sie die Methode acquire() aufrufen. Wenn die Sperre erteilt wurde, drucken Sie „Sperre erworben“ zur Konsole. Sobald die Ausführung des gesamten Codes, den der Thread ausführen soll, abgeschlossen ist, heben Sie die Sperre auf, indem Sie die Methode release() aufrufen.

Die Theorie ist gut, aber woher wissen Sie, dass die Sperre wirklich funktioniert hat? Wenn Sie sich die Ausgabe ansehen, werden Sie feststellen, dass jede der Druckanweisungen jeweils genau eine Zeile ausgibt. Erinnern Sie sich, dass in einem früheren Beispiel die Ausgaben von print zufällig waren, weil mehrere Threads gleichzeitig auf die Methode print() zugegriffen haben. Hier wird die Druckfunktion erst aufgerufen, nachdem die Sperre erhalten wurde. Die Ausgaben werden also einzeln und Zeile für Zeile angezeigt.

Abgesehen von Sperren unterstützt Python auch einige andere Mechanismen zur Handhabung der Thread-Synchronisierung, wie unten aufgeführt:

  1. RLocks
  2. Semaphores
  3. Bedingungen
  4. Veranstaltungen und
  5. Barriers

Global Interpreter Lock (und wie man damit umgeht)

Bevor wir uns mit den Details von Pythons GIL befassen, definieren wir einige Begriffe, die zum Verständnis des nächsten Abschnitts hilfreich sind:

  1. CPU-gebundener Code: Dies bezieht sich auf jeden Codeabschnitt, der direkt von der CPU ausgeführt wird.
  2. E/A-gebundener Code: Dies kann jeder Code sein, der über das Betriebssystem auf das Dateisystem zugreift
  3. CPython: es ist die Referenz Implementierung of Python und kann als der in C geschriebene Interpreter beschrieben werden und Python (Programmiersprache).

Was ist GIL in Python?

Globale Dolmetschersperre (GIL) In Python wird eine Prozesssperre oder ein Mutex beim Umgang mit den Prozessen verwendet. Es stellt sicher, dass jeweils ein Thread auf eine bestimmte Ressource zugreifen kann, und verhindert außerdem die gleichzeitige Verwendung von Objekten und Bytecodes. Dies kommt den Single-Threaded-Programmen in einer Leistungssteigerung zugute. GIL in Python ist sehr einfach und leicht zu implementieren.

Mit einer Sperre kann sichergestellt werden, dass zu einem bestimmten Zeitpunkt nur ein Thread Zugriff auf eine bestimmte Ressource hat.

Eines der Merkmale von Python besteht darin, dass für jeden Interpreterprozess eine globale Sperre verwendet wird, was bedeutet, dass jeder Prozess den Python-Interpreter selbst als Ressource behandelt.

Angenommen, Sie haben ein Python-Programm geschrieben, das zwei Threads verwendet, um sowohl CPU- als auch I/O-Operationen auszuführen. Wenn Sie dieses Programm ausführen, geschieht Folgendes:

  1. Der Python-Interpreter erstellt einen neuen Prozess und erzeugt die Threads
  2. Wenn Thread-1 mit der Ausführung beginnt, erfasst er zunächst die GIL und sperrt sie.
  3. Wenn Thread-2 jetzt ausgeführt werden möchte, muss er auf die Freigabe der GIL warten, auch wenn ein anderer Prozessor frei ist.
  4. Nehmen wir nun an, dass Thread 1 auf eine E/A-Operation wartet. Zu diesem Zeitpunkt gibt er den GIL frei und Thread 2 holt ihn sich.
  5. Wenn Thread-1 nach Abschluss der E/A-Vorgänge jetzt ausgeführt werden möchte, muss er erneut auf die Freigabe der GIL durch Thread-2 warten.

Aus diesem Grund kann jeweils nur ein Thread auf den Interpreter zugreifen, was bedeutet, dass es zu einem bestimmten Zeitpunkt nur einen Thread gibt, der Python-Code ausführt.

Dies ist in einem Single-Core-Prozessor in Ordnung, da für die Verarbeitung der Threads Zeitscheiben (siehe den ersten Abschnitt dieses Tutorials) verwendet würden. Bei Mehrkernprozessoren hat jedoch die Ausführung einer CPU-gebundenen Funktion in mehreren Threads erhebliche Auswirkungen auf die Effizienz des Programms, da nicht alle verfügbaren Kerne gleichzeitig genutzt werden.

Warum wurde GIL benötigt?

Die CPython Der Garbage Collector verwendet eine effiziente Speicherverwaltungstechnik, die als Referenzzählung bekannt ist. So funktioniert es: Jedes Objekt in Python hat einen Referenzzähler, der erhöht wird, wenn ihm ein neuer Variablenname zugewiesen oder es einem Container (wie Tupeln, Listen usw.) hinzugefügt wird. Ebenso wird der Referenzzähler verringert, wenn die Referenz den Gültigkeitsbereich verlässt oder wenn die Anweisung del aufgerufen wird. Wenn der Referenzzähler eines Objekts 0 erreicht, wird es einer Garbage Collection unterzogen und der zugewiesene Speicher wird freigegeben.

Das Problem besteht jedoch darin, dass die Referenzzählvariable wie jede andere globale Variable anfällig für Race Conditions ist. Um dieses Problem zu lösen, entschieden sich die Entwickler von Python, die globale Interpretersperre zu verwenden. Die andere Möglichkeit bestand darin, jedem Objekt eine Sperre hinzuzufügen, was zu Deadlocks und erhöhtem Overhead durch acquire()- und release()-Aufrufe geführt hätte.

Daher stellt GIL eine erhebliche Einschränkung für Multithread-Python-Programme dar, die CPU-lastige Operationen ausführen (und macht sie damit effektiv zu Singlethread-Programmen). Wenn Sie in Ihrer Anwendung mehrere CPU-Kerne nutzen möchten, verwenden Sie die Mehrfachverarbeitung Modul statt.

Zusammenfassung

  • Python unterstützt 2 Module für Multithreading:
    1. __Gewinde Modul: Es bietet eine Low-Level-Implementierung für Threading und ist veraltet.
    2. Threading-Modul: Es bietet eine High-Level-Implementierung für Multithreading und ist der aktuelle Standard.
  • Um einen Thread mit dem Threading-Modul zu erstellen, müssen Sie Folgendes tun:
    1. Erstellen Sie eine Klasse, die das erweitert Thread Klasse.
    2. Überschreiben Sie seinen Konstruktor (__init__).
    3. Überschreiben Sie es Lauf() Methode.
    4. Erstellen Sie ein Objekt dieser Klasse.
  • Ein Thread kann durch Aufrufen von ausgeführt werden Start() Methode.
  • Das beitreten() Mit der Methode können andere Threads blockiert werden, bis die Ausführung dieses Threads (der Thread, für den Join aufgerufen wurde) abgeschlossen ist.
  • Eine Race-Bedingung tritt auf, wenn mehrere Threads gleichzeitig auf eine gemeinsam genutzte Ressource zugreifen oder diese ändern.
  • Es kann vermieden werden durch Syncchronisierende Threads.
  • Python unterstützt 6 Möglichkeiten zum Synchronisieren von Threads:
    1. Schlösser
    2. RLocks
    3. Semaphores
    4. Bedingungen
    5. Veranstaltungen und
    6. Barriers
  • Sperren erlauben nur einem bestimmten Thread, der die Sperre erhalten hat, den Zugriff auf den kritischen Abschnitt.
  • Eine Sperre verfügt über zwei Hauptmethoden:
    1. erwerben(): Der Sperrstatus wird auf gesetzt verschlossen. Wenn es für ein gesperrtes Objekt aufgerufen wird, blockiert es, bis die Ressource frei ist.
    2. freigeben(): Der Sperrstatus wird auf gesetzt entriegelt und kehrt zurück. Wenn es für ein entsperrtes Objekt aufgerufen wird, wird „false“ zurückgegeben.
  • Die globale Interpretersperre ist ein Mechanismus, durch den nur 1 CPython Interpreterprozesse können gleichzeitig ausgeführt werden.
  • Es wurde verwendet, um die Referenzzählfunktion von C zu erleichternPythons' Garbage Collector.
  • Um Python Apps mit intensiven CPU-intensiven Vorgängen sollten Sie das Multiprocessing-Modul verwenden.