并發編程 - 執行緒
1、什么是執行緒
行程:資源單位
執行緒:執行單位
執行緒與行程都是虛擬的概念,只是為了更好地表達某種事物
注意:開啟一個行程,一定會自帶一個執行緒,執行緒才是真正的執行者
2、為什么要使用執行緒
> 為了節省資源的占用
> 多執行緒執行速度非常快
開啟行程會發生什么:
> 啟動行程會產生一個記憶體空間,申請一塊資源
> 會自帶一個主執行緒
> 開啟子行程的速度要比開啟子執行緒的速度慢
開啟執行緒會發生什么:
> 一個行程內可以開啟多個執行緒,從行程的記憶體空間中申請資源
> 節省資源
# 比如開啟三個行程:
# 占用三分記憶體資源
# 比如開啟三個執行緒:
# 從一個記憶體資源中,申請三個小的執行單位
問題1:在單核情況下,開啟多行程有沒有提高執行效率?
沒有,在單核情況下,盡量開啟多執行緒,
問題:IO密集型、計算密集型分別使用什么?
IO密集型:多執行緒
IO(時間由用戶決定):
阻塞:切換+保存狀態
計算密集型:多行程
計算(時間由作業系統定):
計算時間很長:切換+保存狀態
注意:行程與行程之間資料是隔離的,執行緒與執行緒之間的資料是共享的
3、執行緒的兩種創建方式、守護執行緒
守護執行緒的使用方式和守護行程的使用方式一樣,在下面創建執行緒中體現:
第一種方式:直接呼叫Thread類
from threading import Thread # Thread用來創建執行緒 from threading import current_thread # current_thread中含有執行緒的屬性 import time def task(): print(f"start...{current_thread().name}") # current_thread().name 執行緒的名字 time.sleep(1) print(f"end...{current_thread().name}") # current_thread().name 執行緒的名字 if __name__ == '__main__': # 模擬開啟10個子執行緒 for i in range(10): # 開啟子執行緒 t = Thread(target=task) # 加上守護執行緒:主行程結束,代表主執行緒也結束,子執行緒有可能會被回收,將其他執行緒回收資源 t.daemon = True t.start() # 告訴主執行緒等到子執行緒執行完成再執行主執行緒 t.join() print(f"主行程(主執行緒)結束...{current_thread().name}") # current_thread().name 執行緒的名字
執行結果:
start...Thread-1 end...Thread-1 start...Thread-2 end...Thread-2 start...Thread-3 end...Thread-3 start...Thread-4 end...Thread-4 start...Thread-5 end...Thread-5 start...Thread-6 end...Thread-6 start...Thread-7 end...Thread-7 start...Thread-8 end...Thread-8 start...Thread-9 end...Thread-9 start...Thread-10 end...Thread-10 主行程(主執行緒)結束...MainThread
第二種方式:繼承Thread類
from threading import Thread # Thread用來創建執行緒 from threading import current_thread # current_thread中含有執行緒的屬性 import time class MyThread(Thread): def run(self): print(f"start...{current_thread().name}") # current_thread().name 執行緒的名字 time.sleep(1) print(f"end...{current_thread().name}") # current_thread().name 執行緒的名字 if __name__ == '__main__': # 開啟子執行緒 t = MyThread() # 加上守護執行緒:主行程結束,代表主執行緒也結束,子執行緒有可能會被回收,將其他執行緒回收資源 t.daemon = True t.start() # 告訴主執行緒等到子執行緒執行完成再執行主執行緒 t.join() print(f"主行程(主執行緒)結束...{current_thread().name}") # current_thread().name 執行緒的名字
執行結果:
start...Thread-1 end...Thread-1 主行程(主執行緒)結束...MainThread
4、執行緒間資料是互通的
from threading import Thread import time number = 100 def task(): global number number += 100 print("start...") time.sleep(1) print("end...") if __name__ == '__main__': # 開啟子執行緒 t = Thread(target=task) t.start() # 告訴主執行緒等到子執行緒執行完成再執行主執行緒 t.join() print("主行程(主執行緒)開始...") print(number)print("主行程(主執行緒)結束...")
執行結果:
start... end... 主行程(主執行緒)開始... 200 主行程(主執行緒)結束...
5、執行緒互斥鎖
互斥鎖是一把鎖,將并發編程串行,犧牲了效率,保證了資料讀寫安全
多執行緒實作并發會造成資料不安全,可以使用互斥鎖來避免這種問題
例:開啟十個執行緒,對一個資料進行修改
from threading import Thread from threading import Lock import time number = 100 def task(lock): global number # 加鎖 lock.acquire() number2 = number time.sleep(0.5) number = number2 - 1 # 釋放鎖 lock.release() if __name__ == '__main__': lock = Lock() list1 = [] for i in range(10): t = Thread(target=task, args=(lock, )) t.daemon = True t.start() list1.append(t) for t in list1: t.join() print(number)
執行結果:
90
6、執行緒池
作用:用來限制執行緒的數量,保證了硬體跟得上軟體的發展
from concurrent.futures import ThreadPoolExecutor # pool限制一次只能創建10個執行緒,如果要創建50個執行緒,就要分成5次創建 pool = ThreadPoolExecutor(10)
def task(i): print(i) if __name__ == '__main__': # 開啟50個執行緒 for i in range(50):
# submit(函式名, 引數)方法實作并發 pool.submit(task, 123)
執行結果:
123 123 123 123 123 123 123 123 123 123 123123 123 123 123 123 123 123 123123 123 123 123123 123 123 123 123 123 123 123 123 123 123 123123123 123 123 123 123 123 123 123 123 123 123 123 123 123
7、執行緒池中的回呼函式callback
from concurrent.futures import ThreadPoolExecutor # 并發執行的任務 def task1(): return "壹貳弎肆伍陸柒捌玖拾" # 自定義回呼函式 def task2(obj): # obj物件中的result方法會回傳 "壹貳弎肆伍陸柒捌玖拾" result = obj.result() # "壹貳弎肆伍陸柒捌玖拾" print(result) if __name__ == '__main__': pool = ThreadPoolExecutor(5) for i in range(5): # pool.submit(函式名).add_done_callback(回呼函式的名字) # submit(函式名, 函式接收的引數1, 引數2...) pool.submit(task1).add_done_callback(task2)
執行結果:
壹貳弎肆伍陸柒捌玖拾
壹貳弎肆伍陸柒捌玖拾
壹貳弎肆伍陸柒捌玖拾
壹貳弎肆伍陸柒捌玖拾
壹貳弎肆伍陸柒捌玖拾
PS:行程池中的回呼函式和執行緒池中的回呼函式使用方式一樣
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/205841.html
標籤:其他
上一篇:Python爬蟲:B站排行榜視頻播放量,視頻評論量等資料采集
下一篇:awk實作類sql的join操作
