Die Kosten für das Starten eines neuen Threads durch das System sind relativ hoch, da dies eine Interaktion mit dem Betriebssystem erfordert. In diesem Fall kann die Verwendung eines Thread-Pools die Leistung erheblich verbessern. Insbesondere wenn das Programm eine große Anzahl von Threads mit kurzer Lebensdauer erstellen muss, sollten Sie die Verwendung des Thread-Pools in Betracht ziehen. Der Thread-Pool erstellt beim Systemstart eine große Anzahl inaktiver Threads. Solange das Programm eine Funktion an den Thread-Pool sendet, startet der Thread-Pool einen inaktiven Thread, um diese auszuführen. Wenn die Funktion ausgeführt wird, stirbt der Thread nicht ab, sondern kehrt wieder zum Thread-Pool zurück und bleibt im Leerlauf, während er auf die Ausführung der nächsten Funktion wartet.
Die Kosten für das Starten eines neuen Threads durch das System sind relativ hoch, da eine Interaktion mit dem Betriebssystem erforderlich ist. In diesem Fall kann die Verwendung eines Thread-Pools die Leistung erheblich verbessern. Insbesondere wenn das Programm eine große Anzahl von Threads mit kurzer Lebensdauer erstellen muss, sollten Sie die Verwendung des Thread-Pools in Betracht ziehen.
Der Thread-Pool erstellt beim Systemstart eine große Anzahl inaktiver Threads. Solange das Programm eine Funktion an den Thread-Pool sendet, startet der Thread-Pool einen inaktiven Thread, um ihn auszuführen. Wenn die Ausführung der Funktion beendet ist, stirbt der Thread nicht ab, sondern kehrt zum Thread-Pool zurück, bleibt im Leerlauf und wartet auf die Ausführung der nächsten Funktion.
Darüber hinaus kann die Verwendung eines Thread-Pools die Anzahl gleichzeitiger Threads im System effektiv steuern. Wenn das System eine große Anzahl gleichzeitiger Threads enthält, führt dies zu einem starken Rückgang der Systemleistung und sogar zum Ausfall von Python. Der Interpreter stürzt ab und der Parameter für die maximale Anzahl von Threads des Thread-Pools kann steuern, dass die Anzahl gleichzeitiger Threads im System diese Anzahl nicht überschreitet.
Verwendung des Thread-Pools
Die Basisklasse des Thread-Pools ist Executor im concurrent.futures-Modul, nämlich ThreadPoolExecutor und ProcessPoolExecutor, wobei ThreadPoolExecutor zum Erstellen eines Thread-Pools verwendet wird, und ProcessPoolExecutor wird zum Erstellen eines Prozesspools verwendet.
Wenn Sie einen Thread-Pool/Prozesspool verwenden, um die gleichzeitige Programmierung zu verwalten, müssen Sie nur die entsprechende Aufgabenfunktion an den Thread-Pool/Prozesspool senden, und der Thread-Pool/Prozesspool kümmert sich um den Rest.
Execuor bietet die folgenden gängigen Methoden:
submit(fn, *args, **kwargs): Senden Sie die fn-Funktion an den Thread-Pool. *args stellt die an die fn-Funktion übergebenen Parameter dar, *kwargs Gibt an, dass Parameter in Form von Schlüsselwortargumenten an die fn-Funktion übergeben werden.
map(func, *iterables, timeout=None, chunksize=1): Diese Funktion ähnelt der globalen Funktion map(func, *iterables), aber diese Funktion startet mehrere Threads, um die Kartenverarbeitung für iterables sofort auf asynchrone Weise durchzuführen.
shutdown(wait=True): Thread-Pool schließen.
Nachdem das Programm die Aufgabenfunktion an den Thread-Pool übermittelt hat, gibt die Submit-Methode ein Future-Objekt zurück Die Klasse wird hauptsächlich verwendet, um den Rückgabewert der Thread-Aufgabenfunktion abzurufen. Da die Thread-Aufgabe asynchron im neuen Thread ausgeführt wird, entspricht die vom Thread ausgeführte Funktion einer „in Zukunft abzuschließenden“ Aufgabe, die Python verwendet Zukunft zu vertreten.
Tatsächlich gibt es auch in Javas Multithread-Programmierung Zukunft. Die Zukunft ähnelt hier der Zukunft von Java.
Future bietet die folgenden Methoden:
cancel(): Bricht die durch diesen Future dargestellte Thread-Aufgabe ab. Wenn die Aufgabe ausgeführt wird und nicht abgebrochen werden kann, gibt die Methode „False“ zurück. Andernfalls bricht das Programm die Aufgabe ab und kehrt zurück WAHR.
cancelled(): Gibt zurück, ob die durch Future dargestellte Thread-Aufgabe erfolgreich abgebrochen wurde.
running(): Wenn die durch die Zukunft dargestellte Thread-Aufgabe ausgeführt wird und nicht abgebrochen werden kann, gibt diese Methode True zurück.
done(): Wenn die durch Funture dargestellte Thread-Aufgabe erfolgreich abgebrochen oder abgeschlossen wird, gibt diese Methode True zurück.
result(timeout=None): Ruft das Endergebnis ab, das von der Thread-Aufgabe zurückgegeben wird, die durch diese Zukunft dargestellt wird. Wenn Zukunft Wenn die dargestellte Thread-Aufgabe nicht abgeschlossen wurde, blockiert diese Methode den aktuellen Thread, wobei der Timeout-Parameter die maximale Anzahl der zu blockierenden Sekunden angibt.
Exception(timeout=None): Ruft die Ausnahme ab, die durch die Thread-Aufgabe verursacht wird, die durch diese Zukunft dargestellt wird. Wenn die Aufgabe ausnahmslos erfolgreich abgeschlossen wird, kehrt die Methode zurück Keiner.
add_done_callback(fn): Registrieren Sie eine „Callback-Funktion“ für die durch diese Zukunft dargestellte Thread-Aufgabe. Wenn die Aufgabe erfolgreich abgeschlossen wird, löst das Programm automatisch die Fn aus Funktion.
Nachdem ein Thread-Pool aufgebraucht ist, sollte die Methode „shutdown()“ des Thread-Pools aufgerufen werden, die die Abschaltsequenz des Thread-Pools startet. Shutdown() aufrufen Der Thread-Pool nach der Methode erhält keine neuen Aufgaben mehr, sondern schließt alle zuvor übermittelten Aufgaben ab. Wenn alle Aufgaben im Thread-Pool ausgeführt wurden, sterben alle Threads im Thread-Pool.
Die Schritte zur Verwendung eines Thread-Pools zum Ausführen von Thread-Aufgaben sind wie folgt:
Rufen Sie den Konstruktor der ThreadPoolExecutor-Klasse auf, um einen Thread-Pool zu erstellen.
Definieren Sie eine normale Funktion als Thread-Aufgabe.
Rufen Sie die Methode „submit()“ des ThreadPoolExecutor-Objekts auf, um die Thread-Aufgabe zu senden.
Wenn Sie keine Aufgaben übermitteln möchten, rufen Sie die Methode „shutdown()“ des ThreadPoolExecutor-Objekts auf, um den Thread-Pool herunterzufahren.
Das folgende Programm zeigt, wie der Thread-Pool zum Ausführen von Thread-Aufgaben verwendet wird:
from concurrent.futures import ThreadPoolExecutor import threading import time # 定义一个准备作为线程任务的函数 def action(max): my_sum = 0 for i in range(max): print(threading.current_thread().name + ' ' + str(i)) my_sum += i return my_sum # 创建一个包含2条线程的线程池 pool = ThreadPoolExecutor(max_workers=2) # 向线程池提交一个task, 50会作为action()函数的参数 future1 = pool.submit(action, 50) # 向线程池再提交一个task, 100会作为action()函数的参数 future2 = pool.submit(action, 100) # 判断future1代表的任务是否结束 print(future1.done()) time.sleep(3) # 判断future2代表的任务是否结束 print(future2.done()) # 查看future1代表的任务返回的结果 print(future1.result()) # 查看future2代表的任务返回的结果 print(future2.result()) # 关闭线程池 pool.shutdown()
Im obigen Programm erstellt die 13. Codezeile einen Thread-Pool mit zwei Threads. Fügen Sie in den nächsten beiden Codezeilen einfach action() hinzu. Die Funktion wird an den Thread-Pool übermittelt, und der Thread-Pool ist dafür verantwortlich, den Thread zu starten, um die Funktion action () auszuführen. Diese Methode zum Starten von Threads ist sowohl eleganter als auch effizienter.
Wenn das Programm die Funktion action() an den Thread-Pool sendet, gibt die Methode subscribe() das der Aufgabe entsprechende Future-Objekt zurück und das Programm bestimmt sofort die Zukunft done()-Methode, die False zurückgibt (was anzeigt, dass die Aufgabe zu diesem Zeitpunkt noch nicht abgeschlossen ist). Als nächstes pausiert das Hauptprogramm 3 Sekunden lang und ermittelt dann done() von Future2 Wenn die Aufgabe zu diesem Zeitpunkt abgeschlossen ist, gibt die Methode True zurück.
Das Programm verwendet schließlich die result()-Methode von Future, um die von den beiden asynchronen Aufgaben zurückgegebenen Ergebnisse zu erhalten.
Leser können diesen Code selbst ausführen, um die Ergebnisse anzuzeigen, die hier nicht demonstriert werden.
Wenn das Programm die result()-Methode von Future verwendet, um das Ergebnis abzurufen, blockiert diese Methode den aktuellen Thread, wenn kein Timeout angegeben ist. Parameter bleibt der aktuelle Thread blockiert, bis die durch Future dargestellte Aufgabe zurückkehrt.
Ausführungsergebnisse abrufen
Das vorherige Programm hat die result()-Methode von Future aufgerufen, um den Rückgabewert der Thread-Aufgabe abzurufen, aber diese Methode blockiert den aktuellen Hauptthread erst, nachdem die Geldverarbeitungsaufgabe abgeschlossen ist, result(). Die Blockierung der Methode wird aufgehoben.
Wenn das Programm die result()-Methode nicht direkt aufrufen möchte, um den Thread zu blockieren, kann es add_done_callback() von Future verwenden Methode zum Hinzufügen einer Rückruffunktion. Die Rückruffunktion sieht aus wie fn(future). Wenn die Thread-Aufgabe abgeschlossen ist, löst das Programm automatisch die Rückruffunktion aus und übergibt die entsprechende Zukunft Das Objekt wird als Parameter an die Callback-Funktion übergeben.
Das folgende Programm verwendet die Methode add_done_callback(), um den Rückgabewert der Thread-Aufgabe zu erhalten:
from concurrent.futures import ThreadPoolExecutor import threading import time # 定义一个准备作为线程任务的函数 def action(max): my_sum = 0 for i in range(max): print(threading.current_thread().name + ' ' + str(i)) my_sum += i return my_sum # 创建一个包含2条线程的线程池 with ThreadPoolExecutor(max_workers=2) as pool: # 向线程池提交一个task, 50会作为action()函数的参数 future1 = pool.submit(action, 50) # 向线程池再提交一个task, 100会作为action()函数的参数 future2 = pool.submit(action, 100) def get_result(future): print(future.result()) # 为future1添加线程完成的回调函数 future1.add_done_callback(get_result) # 为future2添加线程完成的回调函数 future2.add_done_callback(get_result) print('--------------')
Das obige Hauptprogramm fügt die gleiche Rückruffunktion für Future1 bzw. Future2 hinzu. Diese Rückruffunktion erhält den Rückgabewert, wenn der Thread ausgeführt wird Aufgabe endet.
Die letzte Codezeile im Hauptprogramm druckt eine horizontale Linie. Weil das Programm result() von Future1 und Future2 nicht direkt aufruft Methode, sodass der Haupt-Thread nicht blockiert wird und Sie sofort die horizontalen Linien sehen können, die vom Ausgabe-Haupt-Thread gedruckt werden. Als nächstes sehen Sie zwei neue Threads, die gleichzeitig ausgeführt werden. Wenn die Thread-Aufgabe abgeschlossen ist, wird get_result() aufgerufen. Die Funktion wird ausgelöst und gibt den Rückgabewert der Thread-Aufgabe aus.
Da der Thread-Pool außerdem das Context Manage Protocol implementiert, kann das Programm mit verwenden Anweisung zum Verwalten des Thread-Pools, wodurch die Notwendigkeit vermieden wird, den Thread-Pool manuell zu schließen, wie im obigen Programm gezeigt.
Darüber hinaus stellt Execuor auch eine Map bereit (func, *iterables, timeout=None, chunksize=1) Die Funktion dieser Methode ähnelt der globalen Funktion map(). Der Unterschied besteht darin, dass die Methode map() des Thread-Pools einen Thread für jedes Element von Iterables startet, um func gleichzeitig auszuführen. Funktion. Diese Methode entspricht dem Starten von len(iterables)-Threads und dem Sammeln der Ausführungsergebnisse jedes Threads.
Zum Beispiel verwendet das folgende Programm die Methode „map()“ des Executors, um Threads zu starten und die Rückgabewerte von Thread-Aufgaben zu sammeln:
from concurrent.futures import ThreadPoolExecutor import threading import time # 定义一个准备作为线程任务的函数 def action(max): my_sum = 0 for i in range(max): print(threading.current_thread().name + ' ' + str(i)) my_sum += i return my_sum # 创建一个包含4条线程的线程池 with ThreadPoolExecutor(max_workers=4) as pool: # 使用线程执行map计算 # 后面元组有3个元素,因此程序启动3条线程来执行action函数 results = pool.map(action, (50, 100, 150)) print('--------------') for r in results: print(r)
Das obige Programm verwendet die Methode „map()“, um 3 Threads (die des Programms) zu starten Thread-Pool enthält 4 Threads: Wenn Sie weiterhin einen Thread-Pool mit nur zwei Threads verwenden, befindet sich eine Aufgabe zu diesem Zeitpunkt im Wartezustand, und Sie müssen warten, bis eine der Aufgaben abgeschlossen ist, bevor der Thread frei wird, bevor er ausgeführt werden kann ), Karte() Der Rückgabewert der Methode sammelt die Rückgabeergebnisse jeder Thread-Aufgabe.
Führen Sie das obige Programm aus. Sie können auch die Ergebnisse der gleichzeitigen Ausführung von drei Threads sehen. Schließlich können Sie die Rückgabeergebnisse der drei Thread-Aufgaben durch Ergebnisse sehen.
Wie aus dem obigen Programm ersichtlich ist, hat die Verwendung der Methode map() zum Starten eines Threads und zum Sammeln der Ausführungsergebnisse des Threads nicht nur den Vorteil eines einfachen Codes, sondern auch, obwohl das Programm gleichzeitig action() ausführt Funktion, aber das am Ende gesammelte Ausführungsergebnis der Funktion action() stimmt immer noch mit dem Ergebnis der übergebenen Parameter überein. Das heißt, das erste Element der oben genannten Ergebnisse ist action(50) Das zweite Element ist das Ergebnis von Aktion (100) und das dritte Element ist das Ergebnis von Aktion (150).
Das obige ist der detaillierte Inhalt vonPython-Thread-Pool und seine Prinzipien und Verwendungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!