Ich versuche, das Threading in Python zu verstehen. Ich habe mir die Dokumentation und Beispiele angesehen, aber ehrlich gesagt sind viele Beispiele zu raffiniert und ich habe Probleme, sie zu verstehen.
Wie zeigen Sie deutlich, dass Aufgaben für Multithreading aufgeteilt sind?
Antworten:
Seit diese Frage im Jahr 2010 gestellt wurde, wurde das einfache Multithreading mit Python mit Map und Pool erheblich vereinfacht .
Der folgende Code stammt aus einem Artikel / Blog-Beitrag, den Sie unbedingt lesen sollten (keine Zugehörigkeit) - Parallelität in einer Zeile: Ein besseres Modell für alltägliche Threading-Aufgaben . Ich fasse unten zusammen - es sind nur ein paar Codezeilen:
Welches ist die Multithread-Version von:
Beschreibung
Implementierung
multiprocessing.dummy
ist genau das gleiche wie das Multiprocessing-Modul, verwendet jedoch stattdessen Threads ( ein wichtiger Unterschied - verwenden Sie mehrere Prozesse für CPU-intensive Aufgaben; Threads für (und während) E / A ):Und das Timing ergibt sich:
Übergeben mehrerer Argumente (funktioniert nur in Python 3.3 und höher so ):
So übergeben Sie mehrere Arrays:
Oder um eine Konstante und ein Array zu übergeben:
Wenn Sie eine frühere Version von Python verwenden, können Sie über diese Problemumgehung mehrere Argumente übergeben .
(Danke an user136036 für den hilfreichen Kommentar.)
quelle
with Pool(8) as p: p.map( *whatever* )
und Buchhaltungszeilen loswerden.Hier ist ein einfaches Beispiel: Sie müssen einige alternative URLs ausprobieren und den Inhalt der ersten, die antwortet, zurückgeben.
Dies ist ein Fall, in dem Threading als einfache Optimierung verwendet wird: Jeder Subthread wartet darauf, dass eine URL aufgelöst und beantwortet wird, um seinen Inhalt in die Warteschlange zu stellen. Jeder Thread ist ein Daemon (hält den Prozess nicht aufrecht, wenn der Hauptthread endet - das ist häufiger als nicht). Der Hauptthread startet alle Subthreads, führt
get
in der Warteschlange ein, um zu warten, bis einer von ihnen a ausgeführt hatput
, gibt dann die Ergebnisse aus und wird beendet (wodurch alle Subthreads entfernt werden, die möglicherweise noch ausgeführt werden, da es sich um Daemon-Threads handelt).Die ordnungsgemäße Verwendung von Threads in Python ist ausnahmslos mit E / A-Vorgängen verbunden (da CPython ohnehin nicht mehrere Kerne zum Ausführen von CPU-gebundenen Aufgaben verwendet, besteht der einzige Grund für das Threading darin, den Prozess nicht zu blockieren, während auf einige E / A gewartet wird ). Warteschlangen sind übrigens fast immer der beste Weg, um Arbeit an Threads zu verteilen und / oder die Arbeitsergebnisse zu sammeln. Sie sind an sich threadsicher, sodass Sie sich keine Gedanken über Sperren, Bedingungen, Ereignisse, Semaphoren und andere Interaktionen machen müssen -Thread-Koordinations- / Kommunikationskonzepte.
quelle
join()
Methode zu verwenden, da der Haupt-Thread dann warten würde, bis sie fertig sind, ohne ständig Prozessor zu verbrauchen Überprüfen Sie den Wert. @Alex: Danke, genau das brauchte ich, um zu verstehen, wie man Threads benutzt.Queue
Modulnamen durchqueue
. Der Methodenname ist der gleiche.s = q.get()
print s
führen Sie einfach den folgenden Befehl aus: @ krs013 Sie benötigen das nicht,join
da Queue.get () blockiert.ANMERKUNG : Für die eigentliche Parallelisierung in Python sollten Sie das Multiprocessing- Modul verwenden, um mehrere Prozesse zu verzweigen, die parallel ausgeführt werden (aufgrund der globalen Interpretersperre bieten Python-Threads Interleaving, werden jedoch tatsächlich seriell, nicht parallel und nur ausgeführt nützlich beim Verschachteln von E / A-Operationen).
Wenn Sie jedoch nur nach Verschachtelung suchen (oder E / A-Operationen ausführen, die trotz der globalen Interpretersperre parallelisiert werden können), ist das Threading- Modul der Ausgangspunkt. Betrachten wir als wirklich einfaches Beispiel das Problem der Summierung eines großen Bereichs durch parallele Summierung von Unterbereichen:
Beachten Sie, dass das obige Beispiel ein sehr dummes Beispiel ist, da es absolut keine E / A-Vorgänge ausführt und seriell ausgeführt wird, obwohl es aufgrund der globalen Interpretersperre in CPython verschachtelt ist (mit dem zusätzlichen Aufwand für die Kontextumschaltung) .
quelle
thread1
wird ausgeführt, bis es abgeschlossen ist, während der Haupt-Thread blockiert, dann passiert dasselbe mitthread2
, dann wird der Haupt-Thread fortgesetzt und druckt die akkumulierten Werte aus.super(SummingThread, self).__init__()
? Wie in stackoverflow.com/a/2197625/806988Wie bereits erwähnt, kann CPython Threads nur für E / A-Wartezeiten aufgrund von GIL verwenden .
Wenn Sie für CPU-gebundene Aufgaben von mehreren Kernen profitieren möchten, verwenden Sie Multiprocessing :
quelle
f
funktionieren. Parallel dazu wartet das Hauptprogramm nur noch darauf, dass der Prozess beendet wirdjoin
. Wenn der Hauptteil gerade beendet wurde, wird der Unterprozess möglicherweise vollständig ausgeführt oder nicht. Daherjoin
wird immer empfohlen, a auszuführen .map
Funktion enthält, ist hier: stackoverflow.com/a/28463266/2327328Nur ein Hinweis: Für das Threading ist keine Warteschlange erforderlich.
Dies ist das einfachste Beispiel, das ich mir vorstellen kann und das zeigt, dass 10 Prozesse gleichzeitig ausgeführt werden.
quelle
for
Schleife erforderlich , Sie können diethread.start()
erste Schleife aufrufen .Die Antwort von Alex Martelli hat mir geholfen. Hier ist jedoch eine modifizierte Version, die ich (zumindest für mich) für nützlicher hielt.
Aktualisiert: Funktioniert sowohl in Python 2 als auch in Python 3
quelle
import Queue ModuleNotFoundError: No module named 'Queue'
erhalte : Ich verwende Python 3.6.5. In einigen Posts wird erwähnt, dass es in Python 3.6.5 ist,queue
aber selbst nachdem ich es geändert habe, funktioniert es immer noch nichtFädeln Sie eine gegebene Funktion folgendermaßen ein
f
:Argumente an übergeben
f
quelle
Thread
Objekt beim Beenden der Funktion bereinigt. Siehe die Dokumente . Es gibt eineis_alive()
Methode, mit der Sie bei Bedarf einen Thread überprüfen können.is_alive
Methode gesehen, konnte aber nicht herausfinden, wie ich sie auf den Thread anwenden soll. Ich habe versucht, es zuzuweisenthread1=threading.Thread(target=f).start()
und dann zu überprüfenthread1.is_alive()
, ist aberthread1
mit gefülltNone
, also kein Glück dort. Wissen Sie, ob es eine andere Möglichkeit gibt, auf den Thread zuzugreifen?thread1=threading.Thread(target=f)
gefolgt vonthread1.start()
. Dann können Sie tunthread1.is_alive()
.thread1.is_alive()
RückgabenFalse
, sobald die Funktion beendet wird.Ich fand das sehr nützlich: Erstellen Sie so viele Threads wie Kerne und lassen Sie sie eine (große) Anzahl von Aufgaben ausführen (in diesem Fall ein Shell-Programm aufrufen):
quelle
Python 3 bietet die Möglichkeit, parallele Aufgaben zu starten . Dies erleichtert unsere Arbeit.
Es verfügt über Thread-Pooling und Prozess-Pooling .
Folgendes gibt einen Einblick:
ThreadPoolExecutor Beispiel ( Quelle )
ProcessPoolExecutor ( Quelle )
quelle
Verwenden des brandneuen Moduls concurrent.futures
Der Executor-Ansatz scheint allen bekannt zu sein, die sich zuvor mit Java die Hände schmutzig gemacht haben.
Nebenbei bemerkt: Um das Universum gesund zu halten, vergessen Sie nicht, Ihre Pools / Executoren zu schließen, wenn Sie keinen
with
Kontext verwenden (was so großartig ist, dass es das für Sie tut).quelle
Für mich ist das perfekte Beispiel für das Threading die Überwachung asynchroner Ereignisse. Schauen Sie sich diesen Code an.
Sie können mit diesem Code spielen, indem Sie eine IPython- Sitzung öffnen und Folgendes tun:
Warte ein paar Minuten
quelle
Die meisten Dokumentationen und Tutorials verwenden Pythons
Threading
undQueue
Module und können für Anfänger überwältigend erscheinen.Betrachten Sie vielleicht das
concurrent.futures.ThreadPoolExecutor
Modul von Python 3.In Kombination mit
with
Klausel- und Listenverständnis könnte dies ein echter Reiz sein.quelle
Ich habe hier viele Beispiele gesehen, bei denen keine wirkliche Arbeit ausgeführt wurde und die größtenteils an die CPU gebunden waren. Hier ist ein Beispiel für eine CPU-gebundene Aufgabe, die alle Primzahlen zwischen 10 und 10,05 Millionen berechnet. Ich habe hier alle vier Methoden angewendet:
Hier sind die Ergebnisse auf meinem Mac OS X-Vierkerncomputer
quelle
if __name__ == '__main__':
vor dem Haupt Aufruf, da sonst die Messung Spawns selbst und druckt ein Versuch unternommen wurde , bevor Sie einen neuen Prozess zu starten ... .Hier ist das sehr einfache Beispiel für den CSV- Import mithilfe von Threading. (Die Aufnahme in die Bibliothek kann für verschiedene Zwecke unterschiedlich sein.)
Hilfsfunktionen:
Treiberfunktion:
quelle
Ich möchte mit einem einfachen Beispiel und den Erklärungen, die ich nützlich fand, als ich dieses Problem selbst angehen musste, einen Beitrag leisten.
In dieser Antwort finden Sie einige Informationen zu Pythons GIL (Global Interpreter Lock) und ein einfaches Beispiel aus dem Alltag, das mit multiprocessing.dummy geschrieben wurde, sowie einige einfache Benchmarks.
Global Interpreter Lock (GIL)
Python erlaubt kein Multithreading im wahrsten Sinne des Wortes. Es verfügt über ein Multithreading-Paket. Wenn Sie jedoch ein Multithreading-Paket verwenden möchten, um Ihren Code zu beschleunigen, ist es normalerweise keine gute Idee, es zu verwenden.
Python hat ein Konstrukt namens Global Interpreter Lock (GIL). Die GIL stellt sicher, dass immer nur einer Ihrer 'Threads' gleichzeitig ausgeführt werden kann. Ein Thread erwirbt die GIL, erledigt ein wenig Arbeit und leitet die GIL dann an den nächsten Thread weiter.
Dies geschieht sehr schnell, so dass es für das menschliche Auge so aussieht, als würden Ihre Threads parallel ausgeführt, aber sie wechseln sich nur mit demselben CPU-Kern ab.
All diese GIL-Übergaben erhöhen den Aufwand für die Ausführung. Dies bedeutet, dass die Verwendung des Threading-Pakets häufig keine gute Idee ist, wenn Sie Ihren Code schneller ausführen möchten.
Es gibt Gründe, das Threading-Paket von Python zu verwenden. Wenn Sie einige Dinge gleichzeitig ausführen möchten und Effizienz kein Problem darstellt, ist dies völlig in Ordnung und praktisch. Oder wenn Sie Code ausführen, der auf etwas warten muss (wie z. B. einige E / A), kann dies sehr sinnvoll sein. In der Threading-Bibliothek können Sie jedoch keine zusätzlichen CPU-Kerne verwenden.
Multithreading kann an das Betriebssystem ausgelagert werden (durch Multiverarbeitung) und an eine externe Anwendung, die Ihren Python-Code aufruft (z. B. Spark oder Hadoop ), oder an einen Code, den Ihr Python-Code aufruft (z. B.: Sie könnten Lassen Sie Ihren Python-Code eine C-Funktion aufrufen, die die teuren Multithread-Aufgaben erledigt.
Warum das wichtig ist
Weil viele Leute viel Zeit damit verbringen, Engpässe in ihrem ausgefallenen Python-Multithread-Code zu finden, bevor sie lernen, was die GIL ist.
Sobald diese Informationen klar sind, ist hier mein Code:
quelle
Hier ist Multithreading mit einem einfachen Beispiel, das hilfreich sein wird. Sie können es ausführen und leicht verstehen, wie Multithreading in Python funktioniert. Ich habe eine Sperre verwendet, um den Zugriff auf andere Threads zu verhindern, bis die vorherigen Threads ihre Arbeit beendet haben. Durch die Verwendung dieser Codezeile
Sie können mehrere Prozesse gleichzeitig zulassen und den Rest der Threads beibehalten, die später oder nach Abschluss vorheriger Prozesse ausgeführt werden.
quelle
Wenn wir uns diesen Beitrag ausleihen, wissen wir, wie man zwischen Multithreading, Multiprocessing und Async /
asyncio
und deren Verwendung wählt .Python 3 verfügt über eine neue integrierte Bibliothek für Parallelität und Parallelität: concurrent.futures
Also werde ich durch ein Experiment demonstrieren, wie man vier Aufgaben (dh eine
.sleep()
Methode) auf folgendeThreading-Pool
Weise ausführt:Ausgabe:
[ HINWEIS ]:
multiprocessing
vsthreading
) Sie das ändern könnteThreadPoolExecutor
zuProcessPoolExecutor
.quelle
Keine der vorherigen Lösungen verwendete tatsächlich mehrere Kerne auf meinem GNU / Linux-Server (wo ich keine Administratorrechte habe). Sie liefen nur auf einem einzigen Kern.
Ich habe die
os.fork
Schnittstelle der unteren Ebene verwendet, um mehrere Prozesse zu erzeugen. Dies ist der Code, der für mich funktioniert hat:quelle
quelle