使用 map 來提交多個函數
使用 submit 提交函數會返回一個 future,並且還可以給 future 綁定一個回調。但如果不關心回調的話,那麼還可以使用 map 進行提交。
可以看到,當使用for循環的時候,map 執行的邏輯和 submit 是一樣的。唯一的區別是,此時不需要再調用 result 了,因為返回的就是函數的返回值。
或者我們直接調用 list 也行。
results 是一個生成器,調用 list 的時候會將裡面的值全部產出。由於 map 內部還是使用的 submit,然後通過 future.result() 拿到返回值,而耗時最長的函數需要 3 秒,因此這一步會阻塞 3 秒。3 秒過後,會打印所有函數的返回值。
按照順序等待執行
上面在獲取返回值的時候,是按照函數的提交順序獲取的。如果我希望哪個函數先執行完畢,就先獲取哪個函數的返回值,該怎麼做呢?
此時誰先完成,誰先返回。
取消一個函數的執行
我們通過 submit 可以將函數提交到線程池中執行,但如果我們想取消該怎麼辦呢?
問題來了,調用 cancelled 方法的時候,返回的是False,這是為什麼?很簡單,因為函數已經被提交到線程池裡面了,函數已經運行了。而只有在還沒有運行時,取消才會成功。
可這不矛盾了嗎?函數一旦提交就會運行,只有不運行才會取消成功,這怎麼辦?還記得線程池的一個叫做 max_workers 的參數嗎?用來控制線程池內的線程數量,我們可以將最大的線程數設置為2,那麼當第三個函數進去的時候,就不會執行了,而是處於暫停狀態。
在啟動線程池的時候,肯定是需要設置容量的,不然處理幾千個函數要開啟幾千個線程嗎。另外當函數被取消了,就不可以再調用 future.result() 了,否則的話會拋出 CancelledError。
函數執行時出現異常
我們前面的邏輯都是函數正常執行的前提下,但天有不測風雲,如果函數執行時出現異常了該怎麼辦?
出現異常時,調用 future.set_exception 將異常設置到 future 裡面,而 future 有一個 _exception 屬性,專門保存設置的異常。當調用 future.exception() 時,也會直接返回 _exception 屬性的值。
等待所有函數執行完畢
假設我們往線程池提交了很多個函數,如果希望提交的函數都執行完畢之後,主程序才能往下執行,該怎麼辦呢?其實方案有很多:
第一種:
第二種:
第三種:
第四種:
小結
如果我們需要啟動多線程來執行函數的話,那麼不妨使用線程池。每調用一個函數就從池子裡面取出一個線程,函數執行完畢就將線程放回到池子裡以便其它函數執行。如果池子裡面空了,或者說無法創建新的空閒線程,那麼接下來的函數就只能處於等待狀態了。
最後,concurrent.futures 不僅可以用於實現線程池,還可以用於實現進程池。兩者的 API 是一樣的:
線程池和進程池的 API 是一致的,但工作中很少會創建進程池。
Python全網最熱資料包【華清遠見發放資料包】http://makerschool.mikecrm.com/6cvAGKm
python入門
Python的封裝
Python網絡編程
python高級用法
Python爬蟲開發
python 人工智能-神經網絡
django項目案例精講
雲計算 大數據和人工智能
快速學習爬蟲基礎
爬蟲數據提取