Fluent Python 讀書筆記(六)
註
此筆記適用 Python 3.4,部份已不相容後續版本的套件與 API
以 futures 撰寫並行
- futures —— 非同步執行某項操作的物件
- 網路 I/O 涉及高度延遲,須要用到並行來有效處理
- 在公用 Web 測試並行 HTTP 用戶端,你可能會無意中啟動一個阻斷服務攻擊(DOS),或被懷疑在做這件事…要測試複雜的用戶端,你應該設定自己的測試伺服器(作法說明)
requests
已經被視為 Python 式 API 的典範,它比標準函式庫urllib.request
還要強大concurrent.futures
主要功能是能讓你分別提交(submit)在不同執行緒/程序執行的可呼叫物(callables),實作於ThreadPoolExecutor
、ProcessPoolExecutor
的介面(分別在內部管理一個 worker thread pool 及 process pool)
多執行緒並行起手勢
1 2 3 4 5 6 7 8 9 10 11 12 |
# 以 worker 數量來初始化 with futures.ThreadPoolExecuter(MAX_WORKERS) as executor: # func 函式同時被多個執行緒呼叫,回傳一個產生器 res = executor.map(func, tasks) # executor.__exit__ 方法呼叫 executor.shutdown(wait=True) # 這個動作會被**阻塞**直到所有執行緒都完成 # 迭代取出每一個呼叫的回傳值 # 隱式的 next() 會呼叫每一個 future.result() # 如果有任何執行緒在呼叫時出錯,會在這邊發出例外 result = list(res) |
使用單純迴圈來取代 ThreadPoolExecuter.map
:
1 2 3 4 5 |
with futures.ThreadPoolExecuter(MAX_WORKERS) as a executor: future_stack = [] for task in tasks: future_stack.append(executor.submit(func, task)) |
使用手動呼叫 result 取代隱式的 next 呼叫(阻塞式):
1 2 3 4 |
result = [] for future in future_stack: result.append(future.result()) |
使用 as_completed
取代阻塞式的結果查詢(完成後才產出),必須放在 Context Manager 區塊內,因為預設的 __exit__
會阻塞:
1 2 3 4 5 6 |
with futures.ThreadPoolExecuter(MAX_WORKERS) as a executor: ... result = [] for future in futures.as_completed(future_stack): result.append(future.result()) |