Heim > Artikel > Backend-Entwicklung > Detaillierte Einführung in Multithreading in Python (Codebeispiel)
Dieser Artikel bietet Ihnen eine detaillierte Einführung in Multithreading in Python (Codebeispiele). Ich hoffe, dass er Ihnen als Referenz dienen wird.
In diesem Artikel werden die beim Erlernen von Python auftretenden Probleme und einige häufige Verwendungen beschrieben. Beachten Sie, dass die Python-Version dieser Entwicklungsumgebung 2.7 ist.
Bei der Benennung von Python-Dateien müssen Sie darauf achten, dass kein Konflikt mit dem Standardmodulnamen des Systems entsteht, da sonst ein Fehler gemeldet wird.
Wie im folgenden Beispiel lautet der Dateiname beim Lernen von Threads threading.py
und das Python-Skript ist völlig normal, es wird jedoch der folgende Fehler gemeldet: AttributeError: 'module' object has no attribute 'xxx'
.
threading.py
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_test.py @time: 18/8/25 09:14 """ import threading # 获取已激活的线程数 print(threading.active_count())
Ausführung:
➜ baseLearn python threading/threading.py Traceback (most recent call last): File "threading/threading.py", line 9, in <module> import threading File "/Users/kaiyiwang/Code/python/baseLearn/threading/threading.py", line 12, in <module> print(threading.active_count()) AttributeError: 'module' object has no attribute 'active_count' ➜ baseLearn
Sehen Sie sich die Quelldatei der import
-Bibliothek an und finden Sie die Quelldatei existiert und hat keine Fehler, es gibt auch .pyc
Dateien mit Quelldateien
1 Verwenden Sie beim Benennen des Py-Skripts nicht Python reserviert Wörter oder Modulnamen Das Gleiche wie
-Datei der Bibliothek (da das Py-Skript bei jeder Ausführung eine .pyc-Datei generiert; in dem Fall, in dem die .pyc-Datei bereits generiert wurde Wenn der Code nicht aktualisiert wird, wird pyc beim Ausführen weiterhin verwendet. Löschen Sie daher die .pyc-Datei und führen Sie den Code erneut aus oder suchen Sie eine Umgebung, in der sich der Code befinden kann Führen Sie die .pyc-Datei des aktuellen Computers aus, kopieren Sie sie und ersetzen Sie sie .pyc
um und führen Sie sie dann aus. Es wird kein Fehler gemeldet. threading_test.py
➜ baseLearn python threading/threading_test.py 1 ➜ baseLearnMulti-ThreadingMulti-Threading ist eine effektive Möglichkeit, Programmberechnungen zu beschleunigen
ist schnell und einfach zu starten In diesem Abschnitt zeigen wir Ihnen, wie Sie es verwenden. threading
threading_test.py
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_test.py @time: 18/8/25 09:14 """ import threading # 获取已激活的线程数 # print(threading.active_count()) # 查看所有线程信息 # print(threading.enumerate()) # 查看现在正在运行的线程 # print(threading.current_thread()) def thread_job(): print('This is a thread of %s' % threading.current_thread()) def main(): thread = threading.Thread(target=thread_job,) # 定义线程 thread.start() # 让线程开始工作 if __name__ == '__main__': main()2. Join-FunktionDas Ergebnis, wenn join() nicht hinzugefügt wird Wir lassen die
Thread-Arbeit länger dauern T1
threading_join.py
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_join.py @time: 18/8/25 09:14 """ import threading import time def thread_job(): print('T1 start\n') for i in range(10): time.sleep(0.1) # 任务时间0.1s print("T1 finish\n") def main(): added_thread = threading.Thread(target=thread_job, name='T1') # 定义线程 added_thread.start() # 让线程开始工作 print("all done\n") if __name__ == '__main__': main()Das erwartete Ausgabeergebnis ist die Ausführung in der folgenden Reihenfolge:
T1 start T1 finish all doneAber das tatsächliche laufende Ergebnis Addieren Sie das Ergebnis von join() an:
➜ baseLearn python threading/threading_join.py T1 start all done T1 finish ➜ baseLearnAusgabe
, bevor die Thread-Aufgabe abgeschlossen ist. Wenn Sie der Reihenfolge folgen möchten, können Sie nach dem Starten des Threads all done
darauf aufrufen: join
added_thread.start() added_thread.join() print("all done\n")Ergebnisse drucken:
➜ baseLearn python threading/threading_join.py T1 start T1 finish all doneVollständige Skriptdatei:
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_join.py @time: 18/8/25 09:14 """ import threading import time def thread_job(): print('T1 start\n') for i in range(10): time.sleep(0.1) # 任务时间0.1s print("T1 finish\n") def main(): added_thread = threading.Thread(target=thread_job, name='T1') # 定义线程 added_thread.start() # 让线程开始工作 added_thread.join() print("all done\n") if __name__ == '__main__': main()Versuchen Sie es it outWenn zwei Threads hinzugefügt werden, wie sieht die gedruckte Ausgabe aus? Das von
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_join.py @time: 18/8/25 09:14 """ import threading import time def T1_job(): print('T1 start\n') for i in range(10): time.sleep(0.1) # 任务时间0.1s print("T1 finish\n") def T2_job(): print("T2 start\n") print("T2 finish\n") def main(): thread_1 = threading.Thread(target=T1_job, name='T1') # 定义线程 thread_2 = threading.Thread(target=T2_job, name='T2') # 定义线程 thread_1.start() # 开启T1 thread_2.start() # 开启T2 print("all done\n") if __name__ == '__main__': main()ausgegebene „Eins“-Ergebnis lautet:
T1 start T2 start T2 finish all done T1 finishJetzt hat weder T1 noch T2
. Beachten Sie, dass dort „eins“ steht, da das Auftreten von „all done“ vollständig von zwei abhängt Aufgrund der Ausführungsgeschwindigkeit eines Threads ist es durchaus möglich, dass T2-Finish erscheint, nachdem alles erledigt ist. Wir können diese chaotische Ausführungsmethode nicht tolerieren, daher müssen wir Join verwenden, um sie zu steuern. join
:thread_1.join()
thread_1.start() thread_1.join() # notice the difference! thread_2.start() print("all done\n")nach dem Start von T1 und vor dem Start von T2 hinzuzufügen. Drucken Sie das Ergebnis aus:
T1 start T1 finish T2 start all done T2 finishWie Sie sehen können, wartet T2 auf T1 Fertig. Habe gerade angefangen zu laufen. 3. Warteschlange zum Speichern von ProzessergebnissenImplementierungsfunktionCode zum Implementieren der Funktion, Übergeben der Daten in der Datenliste, Verwenden von vier Threads zur Verarbeitung und Speichern Sie das Ergebnis in der Warteschlange. Nachdem der Thread ausgeführt wurde, erhalten Sie das gespeicherte Ergebnis aus der Warteschlange. Definieren Sie ein
in der Multithread-Funktion, um den Rückgabewert zu speichern. Queue
, definieren Sie ein Multi -Thread-Liste und Initialisierung einer mehrdimensionalen Datenliste, die zur Verarbeitung verwendet wird: 代替return
threading_queue.py
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_queue.py @time: 18/8/25 09:14 """ import threading import time from queue import Queue def job(l, q): for i in range(len(l)): l[i] = l[i] ** 2 q.put(l) #多线程调用的函数不能用return返回值 def multithreading(): q = Queue() #q中存放返回值,代替return的返回值 threads = [] data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]] for i in range(4): #定义四个线程 t = threading.Thread(target=job, args=(data[i], q)) #Thread首字母要大写,被调用的job函数没有括号,只是一个索引,参数在后面 t.start() #开始线程 threads.append(t) #把每个线程append到线程列表中 for thread in threads: thread.join() results = [] for _ in range(4): results.append(q.get()) #q.get()按顺序从q中拿出一个值 print(results) if __name__ == '__main__': multithreading()Beim Ausführen des obigen Skripts ist ein Fehler aufgetreten:
➜ baseLearn python threading/threading_queue.py Traceback (most recent call last): File "threading/threading_queue.py", line 11, in <module> from queue import Queue ImportError: No module named queueDanach Bei der Überprüfung des Grunds wurde festgestellt, dass das Modul durch die Python-Version verursacht wurde. In Python 3 wurde es umbenannt, um den PEP8-Richtlinien zu folgen (alles in Kleinbuchstaben für Modulnamen), sodass die Klasse in der Warteschlange verbleibt alle Versionen (nach PEP8).
Typischerweise würden Sie portierbare Versionsimporte wie folgt schreiben:
In Python3 so zitiert: >
try: import queue except ImportError: import Queue as queueIn Python2 können wir Zitat wie folgt:
from Queue import QueueDrucken:
baseLearn python ./threading/threading_queue.py [[1, 4, 9], [9, 16, 25], [16, 16, 16], [25, 25, 25]]Vollständiger Code:
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_queue.py @time: 18/8/25 09:14 """ import threading # import time from Queue import Queue def job(l, q): for i in range(len(l)): l[i] = l[i] ** 2 q.put(l) #多线程调用的函数不能用return返回值 def multithreading(): q = Queue() #q中存放返回值,代替return的返回值 threads = [] data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]] for i in range(4): #定义四个线程 t = threading.Thread(target=job, args=(data[i], q)) #Thread首字母要大写,被调用的job函数没有括号,只是一个索引,参数在后面 t.start() #开始线程 threads.append(t) #把每个线程append到线程列表中 for thread in threads: thread.join() results = [] for _ in range(4): results.append(q.get()) #q.get()按顺序从q中拿出一个值 print(results) if __name__ == '__main__': multithreading()4. GIL-Effizienzproblem
Was ist GIL ? threading_queue.py
我们创建一个 job
, 分别用 threading 和 一般的方式执行这段程序. 并且创建一个 list 来存放我们要处理的数据. 在 Normal 的时候, 我们这个 list 扩展4倍, 在 threading 的时候, 我们建立4个线程, 并对运行时间进行对比.
threading_gil.py
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_gil.py @time: 18/8/25 09:14 """ import threading from Queue import Queue import copy import time def job(l, q): res = sum(l) q.put(l) #多线程调用的函数不能用return返回值 def multithreading(l): q = Queue() #q中存放返回值,代替return的返回值 threads = [] for i in range(4): #定义四个线程 t = threading.Thread(target=job, args=(copy.copy(l), q), name="T%i" % i) #Thread首字母要大写,被调用的job函数没有括号,只是一个索引,参数在后面 t.start() #开始线程 threads.append(t) #把每个线程append到线程列表中 [t.join() for t in threads] total = 0 for _ in range(4): total = q.get() #q.get()按顺序从q中拿出一个值 print(total) def normal(l): total = sum(l) print(total) if __name__ == '__main__': l = list(range(1000000)) s_t = time.time() normal(l*4) print('normal:', time.time() - s_t) s_t = time.time() multithreading(l) print('multithreading: ', time.time() - s_t)
如果你成功运行整套程序, 你大概会有这样的输出. 我们的运算结果没错, 所以程序 threading 和 Normal 运行了一样多次的运算. 但是我们发现 threading 却没有快多少, 按理来说, 我们预期会要快3-4倍, 因为有建立4个线程, 但是并没有. 这就是其中的 GIL 在作怪.
1999998000000 normal: 0.10034608840942383 1999998000000 multithreading: 0.08421492576599121
threading_lock.py
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_lock.py @time: 18/8/25 09:14 """ import threading # 全局变量A的值每次加1,循环10次,并打印 def job1(): global A for i in range(10): A+=1 print('job1',A) # 全局变量A的值每次加10,循环10次,并打印 def job2(): global A for i in range(10): A+=10 print('job2',A) # 定义两个线程,分别执行函数一和函数二 if __name__== '__main__': A=0 t1=threading.Thread(target=job1) t2=threading.Thread(target=job2) t1.start() t2.start() t1.join() t2.join()
打印输出数据:
➜ baseLearn python ./threading/threading_lock.py ('job1', ('job2'1) , (11)'job1' ('job2', 22) ('job2', 32) ('job2', 42) ('job2', 52) ('job2', 62) ('job2', 72) ('job2', 82) ('job2', 92) ('job2', 102) , 12) ('job1', 103) ('job1', 104) ('job1', 105) ('job1', 106) ('job1', 107) ('job1', 108) ('job1', 109) ('job1', 110)
可以看出,打印的结果非常混乱
lock在不同线程使用同一共享内存
时,能够确保线程之间互不影响,使用lock的方法是, 在每个线程执行运算修改共享内存之前,执行lock.acquire()
将共享内存上锁, 确保当前线程执行时,内存不会被其他线程访问,执行运算完毕后,使用lock.release()
将锁打开, 保证其他的线程可以使用该共享内存。
函数一和函数二加锁
def job1(): global A,lock lock.acquire() for i in range(10): A+=1 print('job1',A) lock.release() def job2(): global A,lock lock.acquire() for i in range(10): A+=10 print('job2',A) lock.release()
主函数中定义一个Lock
if __name__== '__main__': lock=threading.Lock() A=0 t1=threading.Thread(target=job1) t2=threading.Thread(target=job2) t1.start() t2.start() t1.join() t2.join()
完整代码:
# -*- coding:utf-8 -*- """ @author: Corwien @file: threading_lock.py @time: 18/8/25 09:14 """ import threading def job1(): global A,lock lock.acquire() for i in range(10): A+=1 print('job1',A) lock.release() def job2(): global A,lock lock.acquire() for i in range(10): A+=10 print('job2',A) lock.release() if __name__== '__main__': lock = threading.Lock() A=0 t1=threading.Thread(target=job1) t2=threading.Thread(target=job2) t1.start() t2.start() t1.join() t2.join()
打印输出:
➜ baseLearn python ./threading/threading_lock.py ('job1', 1) ('job1', 2) ('job1', 3) ('job1', 4) ('job1', 5) ('job1', 6) ('job1', 7) ('job1', 8) ('job1', 9) ('job1', 10) ('job2', 20) ('job2', 30) ('job2', 40) ('job2', 50) ('job2', 60) ('job2', 70) ('job2', 80) ('job2', 90) ('job2', 100) ('job2', 110)
从打印结果来看,使用lock
后,一个一个线程执行完。使用lock
和不使用lock,最后打印输出的结果是不同的。
相关推荐:
Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in Multithreading in Python (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!