Verfahren
Mehrere Threads in Python sind eigentlich keine echten Multi-Threads. Wenn Sie die Ressourcen einer Multi-Core-CPU voll ausnutzen möchten, müssen Sie in Python in den meisten Fällen mehrere Prozesse verwenden. Python bietet ein sehr benutzerfreundliches Multiprocessing-Paket. Sie müssen nur eine Funktion definieren und Python erledigt alles andere. Mit Hilfe dieses Pakets lässt sich die Umstellung von Einzelprozess auf gleichzeitige Ausführung problemlos bewerkstelligen. Multiprocessing unterstützt Unterprozesse, die Kommunikation und den Austausch von Daten, führt verschiedene Formen der Synchronisierung durch und stellt Komponenten wie Prozess, Warteschlange, Pipe und Sperre bereit.
1. Klassenprozess
Erstellen Sie eine Prozessklasse: Process([group [, target [, name [, args [, kwargs]]]]])
Ziel stellt das aufrufende Objekt dar
Argumente Ein Tupel von Positionsparametern, die das aufrufende Objekt darstellen
kwargs, die ein Wörterbuch des aufrufenden Objekts darstellen
Name ist ein Alias
Gruppe wird im Wesentlichen nicht verwendet
Schauen wir uns die Erstellung der folgenden Funktion an und führen sie als mehrere Prozesse aus Beispiel:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- import multiprocessing import time def worker(interval, name): print(name + '【start】') time.sleep(interval) print(name + '【end】') if __name__ == "__main__": p1 = multiprocessing.Process(target=worker, args=(2, '两点水1')) p2 = multiprocessing.Process(target=worker, args=(3, '两点水2')) p3 = multiprocessing.Process(target=worker, args=(4, '两点水3')) p1.start() p2.start() p3.start() print("The number of CPU is:" + str(multiprocessing.cpu_count())) for p in multiprocessing.active_children(): print("child p.name:" + p.name + "\tp.id" + str(p.pid)) print("END!!!!!!!!!!!!!!!!!")
Ausgabeergebnisse:
Multiprozess-Ausgabeergebnisse
2. Erstellen Sie den Prozess als Klasse
Von Natürlich können wir einen Prozess auch als Klasse erstellen, wie im folgenden Beispiel, wenn der Prozess Wenn p start() aufruft, wird automatisch die run()-Methode aufgerufen.
# -*- coding: UTF-8 -*- import multiprocessing import time class ClockProcess(multiprocessing.Process): def __init__(self, interval): multiprocessing.Process.__init__(self) self.interval = interval def run(self): n = 5 while n > 0: print("当前时间: {0}".format(time.ctime())) time.sleep(self.interval) n -= 1 if __name__ == '__main__': p = ClockProcess(3) p.start()
Die Ausgabeergebnisse lauten wie folgt:
Prozessklasse erstellen
3. Daemon-Attribut
Möchten Sie wissen, was das ist? Daemon-Attribut wird verwendet? Schauen Sie sich die folgenden zwei Beispiele an. Attribut, eines wurde nicht hinzugefügt, vergleichen Sie das Ausgabeergebnis:
Beispiel für das Nichthinzufügen eines Deamon-Attributs:
# -*- coding: UTF-8 -*- import multiprocessing import time def worker(interval): print('工作开始时间:{0}'.format(time.ctime())) time.sleep(interval) print('工作结果时间:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.start() print('【EMD】')
Ausgabeergebnis:
【EMD】 工作开始时间:Mon Oct 9 17:47:06 2017 工作结果时间:Mon Oct 9 17:47:09 2017
Im obigen Beispiel fügt Prozess p hinzu Daemon Attribut:
# -*- coding: UTF-8 -*- import multiprocessing import time def worker(interval): print('工作开始时间:{0}'.format(time.ctime())) time.sleep(interval) print('工作结果时间:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.daemon = True p.start() print('【EMD】')
Ausgabeergebnis:
【EMD】
Wenn das Daemon-Attribut dem untergeordneten Prozess hinzugefügt wird, endet laut Ausgabeergebnis auch der untergeordnete Prozess, wenn der Hauptprozess endet. Daher werden keine Informationen über den untergeordneten Prozess gedruckt.
4. Join-Methode
Um mit dem obigen Beispiel fortzufahren: Was sollten wir tun, wenn wir die Ausführung des untergeordneten Threads beenden möchten?
Dann können wir die Join-Methode verwenden. Die Hauptfunktion der Join-Methode besteht darin, den aktuellen Prozess zu blockieren, bis die Ausführung des Prozesses, der die Join-Methode aufruft, abgeschlossen ist, und dann mit der Ausführung des aktuellen Prozesses fortzufahren.
Sehen Sie sich also das Beispiel für das Hinzufügen der Join-Methode an:
import multiprocessing import time def worker(interval): print('工作开始时间:{0}'.format(time.ctime())) time.sleep(interval) print('工作结果时间:{0}'.format(time.ctime())) if __name__ == '__main__': p = multiprocessing.Process(target=worker, args=(3,)) p.daemon = True p.start() p.join() print('【EMD】')
Das Ausgabeergebnis:
工作开始时间:Tue Oct 10 11:30:08 2017 工作结果时间:Tue Oct 10 11:30:11 2017 【EMD】
5, Pool
Wenn viele untergeordnete Prozesse benötigt werden, müssen wir sie dann einzeln erstellen?
Natürlich nicht, wir können die Prozesspoolmethode verwenden, um untergeordnete Prozesse stapelweise zu erstellen.
Das Beispiel ist wie folgt:
# -*- coding: UTF-8 -*- from multiprocessing import Pool import os, time, random def long_time_task(name): print('进程的名称:{0} ;进程的PID: {1} '.format(name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print('进程 {0} 运行了 {1} 秒'.format(name, (end - start))) if __name__ == '__main__': print('主进程的 PID:{0}'.format(os.getpid())) p = Pool(4) for i in range(6): p.apply_async(long_time_task, args=(i,)) p.close() # 等待所有子进程结束后在关闭主进程 p.join() print('【End】')
Das Ausgabeergebnis ist wie folgt:
主进程的 PID:7256 进程的名称:0 ;进程的PID: 1492 进程的名称:1 ;进程的PID: 12232 进程的名称:2 ;进程的PID: 4332 进程的名称:3 ;进程的PID: 11604 进程 2 运行了 0.6500370502471924 秒 进程的名称:4 ;进程的PID: 4332 进程 1 运行了 1.0830621719360352 秒 进程的名称:5 ;进程的PID: 12232 进程 5 运行了 0.029001712799072266 秒 进程 4 运行了 0.9720554351806641 秒 进程 0 运行了 2.3181326389312744 秒 进程 3 运行了 2.5331451892852783 秒 【End】
Eines ist hier zu beachten: Das Pool-Objekt, das join() aufruft Die Methode wartet auf die Ausführung aller untergeordneten Prozesse. Abgeschlossen. Sie müssen close() aufrufen, bevor Sie join() aufrufen. Nach dem Aufruf von close() können Sie keine weiteren Prozesse hinzufügen.
Bitte achten Sie auf die Ausgabeergebnisse. Die untergeordneten Prozesse 0, 1, 2 und 3 werden sofort ausgeführt, während der untergeordnete Prozess 4 auf den Abschluss eines vorherigen untergeordneten Prozesses warten muss Die Standardgröße des Pools liegt bei uns. Auf meinem Computer beträgt sie 4, sodass höchstens 4 Prozesse gleichzeitig ausgeführt werden. Dies ist eine absichtliche Designbeschränkung von Pool, keine Einschränkung des Betriebssystems. Bei Änderung in:
p = Pool(5)
können 5 Prozesse gleichzeitig ausgeführt werden.
6. Kommunikation zwischen Prozessen
Das Betriebssystem stellt viele Mechanismen zur Verfügung, um eine Kommunikation zwischen Prozessen zu erreichen. Das Multiprocessing-Modul von Python umschließt den zugrunde liegenden Mechanismus und bietet mehrere Möglichkeiten zum Datenaustausch, z. B. Queue und Pipes.
Nehmen Sie die Warteschlange als Beispiel und erstellen Sie zwei untergeordnete Prozesse im übergeordneten Prozess. Einer schreibt Daten in die Warteschlange und der andere liest Daten aus der Warteschlange:
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- from multiprocessing import Process, Queue import os, time, random def write(q): # 写数据进程 print('写进程的PID:{0}'.format(os.getpid())) for value in ['两点水', '三点水', '四点水']: print('写进 Queue 的值为:{0}'.format(value)) q.put(value) time.sleep(random.random()) def read(q): # 读取数据进程 print('读进程的PID:{0}'.format(os.getpid())) while True: value = q.get(True) print('从 Queue 读取的值为:{0}'.format(value)) if __name__ == '__main__': # 父进程创建 Queue,并传给各个子进程 q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) # 启动子进程 pw pw.start() # 启动子进程pr pr.start() # 等待pw结束: pw.join() # pr 进程里是死循环,无法等待其结束,只能强行终止 pr.terminate()
Das Ausgabeergebnis lautet:
读进程的PID:13208 写进程的PID:10864 写进 Queue 的值为:两点水 从 Queue 读取的值为:两点水 写进 Queue 的值为:三点水 从 Queue 读取的值为:三点水 写进 Queue 的值为:四点水 从 Queue 读取的值为:四点水