來源:Python爬蟲與資料探勘作者:星期八前言大家好,我是星期八。我們都知道,不管是Java,還是C++,還是Go,還是Python,都是有執行緒這個概念的。但是我們知道,執行緒是不能隨便創建的,就
2021-06-11 15:30:28
來源:Python爬蟲與資料探勘
作者:星期八
前言
大家好,我是星期八。
我們都知道,不管是Java,還是C++,還是Go,還是Python,都是有執行緒這個概念的。
但是我們知道,執行緒是不能隨便創建的,就像每招一個員工一樣,是有代價的,無限制招人肯定最後各種崩潰。
所以通常情況下,我們會引出執行緒池這個概念。
本質就是我就招了幾個固定的員工,給他們派活,某一個人的活幹完了再去任務中心領取新的活。
防止任務太多,一次性招太多工人,最後系統崩潰。
開心一刻
理想的多執行緒
實際的多執行緒
from concurrent.futures import ...
可能也是因為執行緒池這個東西用的越來越多了吧,從Python3.2+之後,就成了內建模組。
對的,直接就能使用,不需要pip進行安裝什麼的。
concurrent.futures下面主要有倆介面。
ThreadPoolExecutor
執行緒池。ProcessPoolExecutor程序池。這裡可沒有什麼所謂的非同步池。
個人看法:雖然非同步的效能很高,但是目前除了Go以外,其他實現的都不是太好,用法上面有些怪異,當然,你們可以說我菜,我承認。
執行緒池
示例程式碼
import time
from concurrent.futures import ThreadPoolExecutor
import random
# max_workers表示工人數量,也就是執行緒池裡面的執行緒數量
pool = ThreadPoolExecutor(max_workers=10)
# 任務列表
task_list = ["任務1", "任務2", "任務3", "任務4", ]
def handler(task_name):
# 隨機睡眠,模仿任務執行時間不確定性
n = random.randrange(5)
time.sleep(n)
print(f"任務內容:{task_name}")
if __name__ == '__main__':
# 遍歷任務,
for task in task_list:
"""
交給函數處理,submit會將所有任務都提交到一個地方,不會阻塞
然後執行緒池裡面的每個執行緒會來取任務,
比如:執行緒池有3個執行緒,但是有5個任務
會先取走三個任務,每個執行緒去處理
其中一個執行緒處理完自己的任務之後,會再來提交過的任務區再拿走一個任務
"""
pool.submit(handler, task)
print("main執行完畢")
執行結果
發現的問題
其實這個就是併發的,不要懷疑,但是你有沒有發現個問題,main先執行,這說明啥?
這說明,我main跑完之後,是不管子執行緒的死活的。
那能不能設定一下,所有的子執行緒都執行完之後,main函數在執行完?
當然可以,需要一個參數即可。
pool.shutdown()
要完成上述的問題,我們需要一個參數,加上這個參數之後。
就可以讓主執行緒等待所有子執行緒執行完之後,主執行緒再執行完。
示例程式碼
...if __name__ == '__main__':# 遍歷任務, for task in task_list: """ 交給函數處理,submit會將所有任務都提交到一個地方 然後執行緒池裡面的每個執行緒會來取任務, 比如:執行緒池有3個執行緒,但是有5個任務 會先取走三個任務,每個執行緒去處理 其中一個執行緒處理完自己的任務之後,會再來提交過的任務區再拿走一個任務 """ pool.submit(handler, task) pool.shutdown() print("main執行完畢")主要就是13行的pool.shutdown()。執行結果
這次結果就是我們想要的了,hhh!!!
add_done_callback
add_done_callback
可以理解為是回撥函數,執行緒執行完之後,會自動呼叫指定的回撥函數。
並且能拿到執行緒執行函數的返回值。
有什麼用,我也沒用過,怪我才疏學淺叭。
示例程式碼
import time
from concurrent.futures import ThreadPoolExecutor
import random
from concurrent.futures._base import Future
# max_workers表示工人數量,也就是執行緒池裡面的執行緒數量
pool = ThreadPoolExecutor(max_workers=10)
# 任務列表
task_list = ["任務1", "任務2", "任務3", "任務4", ]
def handler(task_name):
# 隨機睡眠,模仿任務執行時間不確定性
n = random.randrange(5)
time.sleep(n)
print(f"任務內容:{task_name}")
return f"任務內容:{task_name}"
def done(res: Future):
print("done拿到的返回值:", res.result())
if __name__ == '__main__':
# 遍歷任務,
for task in task_list:
futrue = pool.submit(handler, task) # type:Future
futrue.add_done_callback(done)
pool.shutdown()
print("main執行完畢")
注意:第17,27,28行程式碼!
執行效果
我想,可能通常用在一些善後工作叭。
多程序方式
其實通過上述幾個例子,我們基本是知道怎麼使用上面這個執行緒池了。
但是都知道Python的執行緒,因為GIL(全局直譯器鎖)的原因,是不能併發到多個物理核心上的。
所以是IO密集型的,像爬蟲,讀寫檔案,使用執行緒池是ok的。
但是如果說我就是野,就是頭鐵,非要用Python做計算型應用,像圖片壓縮、視訊流推送,那沒辦法,需要使用多程序池方式。
其實通過concurrent這個介面,可以很方便的創建程序池,只需要修改兩個地方。...
# 改成匯入程序池方式
from concurrent.futures import ProcessPoolExecutor
...
if __name__ == '__main__':
...
# 程序池方式
pool = ProcessPoolExecutor(max_workers=10)
...
只需要修改這倆地方即可,其他和上述用法一摸一樣。
總結
本篇主要講的是Python自帶的執行緒池和程序池。
比較有特色的是,
ThreadPoolExecutor,ProcessPoolExecutor的介面是一樣的。只需要修改匯入的包就行。concurrent的介面主要有pool.submit(),pool.shutdown(),futrue.add_done_callback()。基本這幾個都夠自己用了。
相關文章
來源:Python爬蟲與資料探勘作者:星期八前言大家好,我是星期八。我們都知道,不管是Java,還是C++,還是Go,還是Python,都是有執行緒這個概念的。但是我們知道,執行緒是不能隨便創建的,就
2021-06-11 15:30:28
機器之心釋出機器之心編輯部MAI(Mobile AI Workshop)是由 CVPR 主辦的 Workshop 競賽。近期,來自位元組跳動智慧創作團隊的 ByteScene 團隊在 MAI 2021 實時移動端場景檢測項目
2021-06-11 15:30:09
明敏 發自 凹非寺量子位 報道 | 公眾號 QbitAI你可能想不到,幾坨便便居然可以這麼有價值。最近,《Nature》發表了一篇關於古人類糞便的論文,為研究1型糖尿病、肥胖等疾病提供了
2021-06-11 15:29:58
iOS15 隱藏功能蘋果在推出 iOS15 之後,雖然釋出會上沒有說什麼太大的新功能,但是各路開發者都發掘到了不少隱藏的功能。在近日,又有開發者發現了 iOS15 版本隱藏了全新的 iPhon
2021-06-11 15:29:39
今日,realme在印度推出realme C25s新手機。該機搭載聯發科 Helio G85處理器,基於Android 11的realme UI 2.0,內建6000mAh的大容量電池。 同時,realme C25s配置6.5英寸、H
2021-06-11 15:29:18
作為「1+8+N」戰略中重要的終端之一,MagicBook系列筆記本自發布以來,不斷打破銷量紀錄,引領行業創新,備受市場和消費者的認可。5月初,MagicBook家族迎來了全新的X系列成員,新品承
2021-06-11 15:28:30