緊接着上一篇文章 python 線程池ThreadPoolExecutor(上) 我們繼續對線程池深入一點了解,其實python中關於線程池,一共有兩個模塊:
1.threadpool — 是一個比較老的模塊了,現在雖然還有一些人在用,但已經不再是主流了;
2.concurrent.futures — 目前線程池主要使用這個模塊,主流模塊;
ThreadPoolExecutor常用函數
除了 python 線程池ThreadPoolExecutor(上) 文章中介紹的 submit() / cancel() / done() / result() 函數外,今天還需要額外講解一下另外幾個函數:
1.as_completed
雖然 done() 函數提供了判斷任務是否結束的方法,但是並不是太實用,因爲我們並不知道線程到底什麼時候結束,需要一直判斷每個任務有沒有結束。這時就可以使用 as_completed() 方法一次取出所有任務的結果。
as_completed() 方法是一個生成器,在沒有任務完成的時候,會阻塞,在有某個任務完成的時候,就能繼續執行for循環後面的語句,然後繼續阻塞住,循環到所有的任務結束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # !usr/bin/env python # -*- coding:utf-8 _*- """ @Author:何以解憂 @Blog(個人博客地址): shuopython.com @WeChat Official Account(微信公衆號):猿說python @Github:www.github.com
@File:python_ThreadPoolExecutor.py @Time:2019/12/07 21:25
@Motto:不積跬步無以至千里,不積小流無以成江海,程序人生的精彩需要堅持不懈地積累! """
from concurrent.futures import ThreadPoolExecutor, as_completed import time
# 參數times用來模擬網絡請求的時間 def download_video(index): time.sleep(2) print("download video {} finished at {}".format(index,time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()))) return index
executor = ThreadPoolExecutor(max_workers=2) urls = [1, 2, 3, 4, 5] all_task = [executor.submit(download_video, (url)) for url in urls]
for task in as_completed(all_task): data = task.result() print("任務{} down load success".format(data)) |
輸出結果:
1 2 3 4 5 6 7 8 9 10 | download video 1 finished at 2019-12-07 02:33:00 任務1 down load success download video 2 finished at 2019-12-07 02:33:00 任務2 down load success download video 3 finished at 2019-12-07 02:33:02 任務3 down load success download video 4 finished at 2019-12-07 02:33:02 任務4 down load success download video 5 finished at 2019-12-07 02:33:04 任務5 down load success |
代碼分析:
5個任務,2個線程,由於在線程池構造的時候允許同時最多執行2個線程,所以同時執行任務1和任務2,重代碼的輸出結果來看,任務1和任務2執行後,for循環進入阻塞狀態,直到任務1或者任務2結束之後纔會for纔會繼續執行任務3/任務4,並保證同時執行的最多隻有兩個任務(關於自定義時間格式請參考: python time模塊).
2.map
和as_completed() 方法不同的是:map()方法能保證任務的順序性,舉個例子:如果同時下載5個視頻,就算第二個視頻比第一個視頻先下載完成,也會阻塞等待第一個視頻下載完成並通知主線程之後,第二個下載完成的視頻纔回通知主線程,保證按照順序完成任務,下面舉個例子說明一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from concurrent.futures import ThreadPoolExecutor, as_completed import time
# 參數times用來模擬網絡請求的時間 def download_video(index): time.sleep(index) print("download video {} finished at {}".format(index,time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()))) return index
executor = ThreadPoolExecutor(max_workers=2) urls = [3, 2, 1, 4, 5]
for data in executor.map(download_video,urls): print("任務{} down load success".format(data)) |
輸出結果:
1 2 3 4 5 6 7 8 9 10 | download video 2 finished at 2019-12-07 03:38:55 download video 3 finished at 2019-12-07 03:38:56 任務3 down load success 任務2 down load success download video 1 finished at 2019-12-07 03:38:56 任務1 down load success download video 4 finished at 2019-12-07 03:39:00 任務4 down load success download video 5 finished at 2019-12-07 03:39:01 任務5 down load success |
代碼分析:
重上面的輸出結果看來,即便任務2比任務3先完成,for循環輸出的內容依舊是提示先完成的任務3再完成任務2,根據列表urls順序輸出,保證任務的順序性!
3.wait
wait()方法有點類似線程的join()方法,能阻塞主線程,直到線程池中的所有的線程都操作完成!實例代碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED, FIRST_COMPLETED import time
# 參數times用來模擬網絡請求的時間 def download_video(index): time.sleep(2) print("download video {} finished at {}".format(index,time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()))) return index
executor = ThreadPoolExecutor(max_workers=2) urls = [1, 2, 3, 4, 5] all_task = [executor.submit(download_video,(url)) for url in urls]
wait(all_task,return_when=ALL_COMPLETED)
print("main ") |
輸出結果:
1 2 3 4 5 6 | download video 2 finished at 2019-12-07 03:50:22 download video 1 finished at 2019-12-07 03:50:22 download video 3 finished at 2019-12-07 03:50:24 download video 4 finished at 2019-12-07 03:50:24 download video 5 finished at 2019-12-07 03:50:26 main |
wait
方法接收3個參數,等待的任務序列、超時時間以及等待條件。等待條件return_when
默認爲ALL_COMPLETED
,表明要等待所有的任務都結束。可以看到運行結果中,確實是所有任務都完成了,主線程纔打印出main
。等待條件還可以設置爲FIRST_COMPLETED
,表示第一個任務完成就停止等待。
猜你喜歡:
3.python __name__ == ‘__main__’詳細解釋
轉載請註明:猿說Python » python 線程池ThreadPoolExecutor(下)