3.多執行緒.md
阿新 • • 發佈:2021-07-07
多執行緒
程序與執行緒
-
程序:指在系統中執行的一個應用程式,程式一旦執行就是程序;
- 程序:資源分配的最小單位,一個程序至少有一個執行緒
- 執行緒、記憶體、檔案、網路控制代碼
- 記憶體:每個程序的記憶體是相互獨立的
- 檔案/網路控制代碼:他們是所有的程序所共有的,例如開啟同一個檔案,取搶同一個網路埠,這樣的操作是被允許的
- 搶佔資源,導致死鎖
- 程序:資源分配的最小單位,一個程序至少有一個執行緒
-
執行緒:系統分配處理器時間資源的基本單位,或者說程序之內獨立執行的一個單元的執行流。
- 執行緒:程式執行的最小單位
-
彙總:
- 1、程序要分配一大部分的記憶體,而執行緒只需要分配一部分棧就可以了
- 2、一個程式至少有一個程序,一個程序至少有一個執行緒
- 3、程序是資源分配的最小單位,執行緒是程式執行的最小單位
- 4、一個執行緒可以建立和撤銷另一個執行緒,同一個程序中的多個執行緒之間可以併發執行
多執行緒---併發
-
並行:兩個CPU同時做事情
-
併發:一個cpu,從執行A任務,接著執行b任務,又執行a任務,接著又執行b任務,迴圈執行
- 1、使用執行緒可以把佔據長時間的程式中的任務放到後臺去處理
- 2、使用者介面可以更加吸引人,比如使用者點選了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度
- 程式的執行速度可能加快
- 在一些等待的任務實現上如使用者輸入,檔案讀寫和網路收發資料等,執行緒就比較有用了。在這種情況下我們可以釋放一些珍貴的資源如記憶體佔用等等
Threading模組
-
python3執行緒中常用的兩個模組為:
- _thread
- threading(推薦使用)
-
thread模組已經被廢棄了。使用者可以使用threading模組代替。所以,在python3中不能再使用thread模組,為了相容性,python3將thread重新命名為_thread
-
常用方法
- run():用以表示執行緒活動的方法
- start():啟動執行緒的方法
- join([time]):等待至執行緒中止,這阻塞呼叫執行緒直至執行緒的join()方法被呼叫中止--正常退出或者丟擲未處理的異常--或者是可選的超時發生
- isAlive():返回執行緒是否活動的
- getName():返回執行緒名
- setName():設定執行緒名
- threading.currentThread():返回當前的執行緒變數
- threading.enumerate():返回一個包含正在執行的執行緒list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒。
- threading.activeCount():返回正在執行的執行緒數量,與len(threading.enumerate())有相同的效果
多執行緒基礎
import time
def doing(something):
time.sleep(2)
print('正在做>>>',something)
start_time =time.time()
doing('在上課')
doing('在上班')
end_time =time.time()
print('總共耗時>>>',end_time-start_time)
控制檯輸出:
正在做>>> 在上課
正在做>>> 在上班
總共耗時>>> 4.010261297225952
io密集型
#-------------------------------------------------------------
"""
需求:執行效率低
優化:使用多執行緒
io密集型
"""
#-------------------------------------------------------------
def doing(something):
print('正在做>>>', something)
time.sleep(2)
start_time = time.time()
#1-建立執行緒
"""
target:函式名
args:函式名對應的實參,元組形式
"""
t1=threading.Thread(target=doing,args=('在上課',))
t2=threading.Thread(target=doing,args=('在加班',))
#2-啟動執行緒
t1.start()
t2.start()
end_time = time.time()
print('總共耗時>>>', end_time - start_time)
控制檯輸出
正在做>>> 在上課
正在做>>> 在加班總共耗時>>>
0.0009598731994628906
分析發現跟預期結果不一致,預期結果是大概是2s,現在是0s
原因:直接啟動執行緒:主執行緒(main)不等待子執行緒(t1/t2)完成就結束
優化方案:
3-阻塞主執行緒
t1.join()
t2.join()
控制檯輸出
正在做>>> 在上課
正在做>>> 在加班
總共耗時>>> 2.0047731399536133
計算密集型
#-------------------------------------------------------------
"""
需求:執行效率低
優化:使用多執行緒
計算密集型
"""
#-------------------------------------------------------------
def doing():
dataNum=0
for i in range(10000000):
dataNum+=1
start_time = time.time()
#1-建立執行緒
"""
target:你這個執行緒是做什麼,需要執行的函式名
args:函式名對應的實參,元組形式
直接啟動執行緒:主執行緒(main)不等待子執行緒(t1/t2)完成就結束
需求:主執行緒退出之前需要等待子執行緒全部執行完
優化:阻塞主執行緒
序列:總共耗時>>> 1.0268769264221191
"""
#t1=threading.Thread(target=doing,args=('在上課',))
#t2=threading.Thread(target=doing,args=('在加班',))
#
##2-啟動執行緒
#t1.start()
#t2.start()
##3-阻塞主執行緒
#t1.join()
#t2.join()
doing()
doing()
end_time = time.time()
print('總共耗時>>>', end_time - start_time)
控制檯輸出:
總共耗時>>> 1.0268769264221191
多執行緒方式;
改變部分的程式碼
t1=threading.Thread(target=doing)
t2=threading.Thread(target=doing)
#2-啟動執行緒
t1.start()
t2.start()
#3-阻塞主執行緒
t1.join()
t2.join()
控制檯輸出
總共耗時>>> 1.0593979358673096
通過對比發現對應計算密集型來說,使用序列和多執行緒,耗時一樣
對於cpython直譯器GIL(全域性直譯器鎖)),不管多少核 cpu同一時間只能處理一件事
原因:
多執行緒是併發:併發是來回切換執行不同的任務,導致計算密集型執行的時間比序列還長,因為來回切換也需要耗時
守護執行緒:
#-------------------------------------------------------------
"""
需求:執行效率低
優化:使用多執行緒
守護執行緒
主執行緒想滿足一個條件就退出,使用多執行緒直接不能直接退出主執行緒
"""
#-------------------------------------------------------------
def doing():
while True:
print('我在doing')
time.sleep(1)
start_time = time.time()
#1-建立執行緒
"""
target:你這個執行緒是做什麼,需要執行的函式名
args:函式名對應的實參,元組形式
直接啟動執行緒:主執行緒(main)不等待子執行緒(t1/t2)完成就結束
需求:主執行緒退出之前需要等待子執行緒全部執行完
優化:阻塞主執行緒
序列:總共耗時>>> 1.0268769264221191
"""
t1=threading.Thread(target=doing)
t2=threading.Thread(target=doing)
#2-啟動執行緒
t1.start()
t2.start()
#3-阻塞主執行緒
#t1.join()
#t2.join()
end_time = time.time()
for i in range(3):
print('**********主執行緒正在執行*******')
print('**********主執行緒結束*******')
print('總共耗時>>>', end_time - start_time)
控制檯輸出:
死迴圈
我在doing
我在doing**********主執行緒正在執行*******
**********主執行緒正在執行*******
**********主執行緒正在執行*******
**********主執行緒結束*******
總共耗時>>> 0.0009987354278564453
我在doing我在doing
我在doing我在doing
我在doing我在doing
我在doing我在doing
我在doing我在doing
分析:
主執行緒一直無法退出
優化:
增加守護執行緒 setdaemon(True)
在以下位置增加守護部分程式碼
t1=threading.Thread(target=doing)
t2=threading.Thread(target=doing)
t1.setDaemon(True)#守護
t2.setDaemon(True)
#2-啟動執行緒
t1.start()
t2.start()
控制檯輸出
我在doing
我在doing
**********主執行緒正在執行*******
**********主執行緒正在執行*******
**********主執行緒正在執行*******
**********主執行緒結束*******
總共耗時>>> 0.0009744167327880859