Wie funktionieren Threads in Python und welche typischen Fallstricke gibt es beim Python-Threading?

StackOverflow https://stackoverflow.com/questions/31340

  •  09-06-2019
  •  | 
  •  

Frage

Ich habe versucht, mich mit der Funktionsweise von Threads in Python auseinanderzusetzen, und es ist schwierig, gute Informationen darüber zu finden, wie sie funktionieren.Möglicherweise fehlt mir nur ein Link oder ähnliches, aber die offizielle Dokumentation scheint zu diesem Thema nicht sehr ausführlich zu sein, und ich konnte keinen guten Artikel finden.

Soweit ich das beurteilen kann, kann nur ein Thread gleichzeitig ausgeführt werden und der aktive Thread wechselt etwa alle 10 Anweisungen?

Wo gibt es eine gute Erklärung oder können Sie eine geben?Es wäre auch sehr schön, sich der häufigen Probleme bewusst zu sein, die bei der Verwendung von Threads mit Python auftreten.

War es hilfreich?

Lösung

Ja, aufgrund der Global Interpreter Lock (GIL) kann jeweils nur ein Thread ausgeführt werden.Hier sind einige Links mit einigen Erkenntnissen dazu:

Aus dem letzten Link ein interessantes Zitat:

Lassen Sie mich erklären, was das alles bedeutet.Themen laufen in derselben virtuellen Maschine und somit auf derselben physischen Maschine.Prozesse können auf derselben physischen Maschine oder in einer anderen physischen Maschine ausgeführt werden.Wenn Sie Ihre Anwendung in Threads architektieren, haben Sie nichts unternommen, um auf mehrere Maschinen zuzugreifen.Sie können also so viele Kerne auf der einzelnen Maschine skalieren (was im Laufe der Zeit einige sein wird), aber um die Webskalen wirklich zu erreichen, müssen Sie das Problem mit mehreren Maschinen trotzdem lösen.

Wenn Sie Multicore verwenden möchten, pyprocessing definiert eine prozessbasierte API, um echte Parallelisierung durchzuführen.Der PEP enthält auch einige interessante Benchmarks.

Andere Tipps

Python lässt sich relativ einfach einbinden, es gibt jedoch Einschränkungen.Das Wichtigste, was Sie wissen müssen, ist die Global Interpreter Lock.Dadurch kann nur ein Thread auf den Interpreter zugreifen.Das bedeutet zwei Dinge:1) In Python kommt es selten vor, dass Sie eine Lock-Anweisung verwenden, und 2) wenn Sie Multiprozessorsysteme nutzen möchten, müssen Sie separate Prozesse verwenden.BEARBEITEN:Ich sollte auch darauf hinweisen, dass Sie einen Teil des Codes in C/C++ einfügen können, wenn Sie auch die GIL umgehen möchten.

Daher müssen Sie noch einmal darüber nachdenken, warum Sie Threads verwenden möchten.Wenn Sie Ihre App parallelisieren möchten, um die Vorteile der Dual-Core-Architektur zu nutzen, müssen Sie darüber nachdenken, Ihre App in mehrere Prozesse aufzuteilen.

Wenn Sie die Reaktionsfähigkeit verbessern möchten, sollten Sie die Verwendung von Threads in Betracht ziehen.Es gibt jedoch auch andere Alternativen, nämlich Mikrothreading.Es gibt auch einige Frameworks, die Sie sich ansehen sollten:

Nachfolgend finden Sie ein einfaches Threading-Beispiel.Es werden 20 Threads erzeugt;Jeder Thread gibt seine Thread-Nummer aus.Führen Sie es aus und beobachten Sie die Reihenfolge, in der sie gedruckt werden.

import threading
class Foo (threading.Thread):
    def __init__(self,x):
        self.__x = x
        threading.Thread.__init__(self)
    def run (self):
          print str(self.__x)

for x in xrange(20):
    Foo(x).start()

Wie Sie angedeutet haben, werden Python-Threads durch Time-Slicing implementiert.Dadurch entsteht der „parallele“ Effekt.

In meinem Beispiel erweitert meine Foo-Klasse den Thread, den ich dann umsetze run Methode, in der der Code abgelegt wird, den Sie in einem Thread ausführen möchten.Um den Thread zu starten, rufen Sie auf start() auf dem Thread-Objekt, das automatisch das aufruft run Methode...

Das sind natürlich nur die Grundlagen.Möglicherweise möchten Sie etwas über Semaphoren, Mutexe und Sperren für die Thread-Synchronisierung und Nachrichtenweitergabe erfahren.

Verwenden Sie Threads in Python, wenn die einzelnen Worker E/A-gebundene Vorgänge ausführen.Wenn Sie versuchen, über mehrere Kerne auf einer Maschine zu skalieren, finden Sie entweder eine gute Lösung IPC Framework für Python oder wählen Sie eine andere Sprache.

Notiz: wo immer ich es erwähne thread ich meine konkret Threads in Python bis es ausdrücklich angegeben wird.

Threads funktionieren in Python etwas anders, wenn Sie von dort kommen C/C++ Hintergrund.In Python kann jeweils nur ein Thread gleichzeitig ausgeführt werden. Dies bedeutet, dass Threads in Python die Leistung mehrerer Verarbeitungskerne nicht wirklich nutzen können, da es konstruktionsbedingt nicht möglich ist, dass Threads parallel auf mehreren Kernen ausgeführt werden.

Da die Speicherverwaltung in Python nicht threadsicher ist, benötigt jeder Thread einen exklusiven Zugriff auf Datenstrukturen im Python-Interpreter. Dieser exklusive Zugriff wird durch einen Mechanismus namens „ GIL (Globale Interpretersperre).

Why does python use GIL?

Um zu verhindern, dass mehrere Threads gleichzeitig auf den Interpreterstatus zugreifen und den Interpreterstatus beschädigen.

Die Idee ist, wann immer ein Thread ausgeführt wird (auch wenn es der Hauptthread ist), ein Gil wird erworben und nach einem vordefinierten Zeitintervall der Zeit wird der GIL durch den aktuellen Faden freigesetzt und von einem anderen Thread (falls vorhanden) wieder vorbereitet.

Why not simply remove GIL?

Es ist nicht unmöglich, GIL zu entfernen, es ist nur so, dass wir dabei am Ende mehrere Sperren in den Interpreter einfügen, um den Zugriff zu serialisieren, was selbst eine Anwendung mit nur einem Thread weniger leistungsfähig macht.

Daher werden die Kosten für die Entfernung von GIL durch die verringerte Leistung einer Single-Thread-Anwendung ausgeglichen, was niemals erwünscht ist.

So when does thread switching occurs in python?

Der Threadwechsel erfolgt, wenn GIL freigegeben wird. Wann wird GIL freigegeben?Es sind zwei Szenarien zu berücksichtigen.

Wenn ein Thread CPU-gebundene Vorgänge ausführt (z. B. Bildverarbeitung).

In älteren Python-Versionen erfolgte der Thread-Wechsel nach einer festen Anzahl von Python-Anweisungen. Standardmäßig war er auf eingestellt 100Es stellte sich heraus 100 Anweisungen unabhängig von der Zeit, die sie zur Ausführung benötigen, ist eine schlechte Richtlinie.

In neuen Versionen wird anstelle der Befehlsanzahl als Metrik zum Wechseln des Threads ein konfigurierbares Zeitintervall verwendet.Das Standardwechselintervall beträgt 5 Millisekunden. Sie können das aktuelle Wechselintervall mit abrufen sys.getswitchinterval().Dies kann mit geändert werden sys.setswitchinterval()

Wenn ein Thread einige IO-gebundene Vorgänge ausführt (Ex-Dateisystemzugriff oder
Netzwerk-IO)

GIL wird immer dann freigegeben, wenn der Thread darauf wartet, dass ein E/A-Vorgang abgeschlossen wird.

Which thread to switch to next?

Der Interpreter verfügt nicht über einen eigenen Scheduler. Welcher Thread am Ende des Intervalls eingeplant wird, liegt in der Entscheidung des Betriebssystems..

Eine einfache Lösung für die GIL ist die Mehrfachverarbeitung Modul.Es kann als Ersatz für das Threading-Modul verwendet werden, verwendet jedoch mehrere Interpreter-Prozesse anstelle von Threads.Aus diesem Grund ist der Overhead für einfache Dinge etwas höher als beim einfachen Threading, aber es bietet Ihnen den Vorteil einer echten Parallelisierung, wenn Sie diese benötigen.Es lässt sich auch problemlos auf mehrere physische Maschinen skalieren.

Wenn Sie eine wirklich groß angelegte Parallelisierung benötigen, würde ich weiter suchen. Wenn Sie jedoch nur auf alle Kerne eines oder einiger verschiedener Computer skalieren möchten, ohne den ganzen Aufwand, der für die Implementierung eines umfassenderen Frameworks erforderlich wäre, dann ist dies das Richtige für Sie .

Denken Sie daran, dass die GIL so eingestellt ist, dass sie von Zeit zu Zeit abfragt, um das Erscheinungsbild mehrerer Aufgaben anzuzeigen.Diese Einstellung kann fein abgestimmt werden, aber ich schlage vor, dass die Threads Arbeit leisten sollten, sonst würden viele Kontextwechsel Probleme verursachen.

Ich würde sogar so weit gehen, mehrere übergeordnete Prozessoren vorzuschlagen und zu versuchen, ähnliche Jobs auf denselben Kernen zu behalten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top