如上一篇文章筆記的Future顧名思義代表未完成的結果,像一張訂單或是掛號信,表示「這個任務已經開始執行了,這是它的結果將來會存放的地方,可以隨時來查詢它的狀態或最終的結果。」
但是還有許多特點沒有紀錄到,例如之前只記錄了兩種Executor分別使用多執行續和多行程來達成concurrent,缺少了Executor本身的筆記,所以又補了篇文章。
Executor物件
- 提供非同步執行呼叫方法的抽象類別。因是抽象類別所以不能直接使用,要透過具體子類別也就是ThreadPoolExecutor或ProcessPoolExecutor來使用。
submit()
- 提交單一任務到Executor,會立即返回一個Future物件,而不等待任務完成。
- 優點是non-blocking,可以繼續做其他事情,稍後需要結果時再處理這個 Future 物件。
as_complete()
- 本身不提交任務,接受一個包含多個 Future 物件的列表或可迭代對象,並以任務完成的順序來回傳它們。
- 會去監聽future物件的狀態是否為完成,完成即回傳。
map()
- 抽象化複雜性:可將 submit()、Future 物件的管理,以及結果收集等非同步流程全部包裝起來。
- 保有 non-blocking 的優點,同時仍保持回傳結果的順序性。
- 抽象化了以下步驟:
- concurrent啟動:將所有任務submit到executor中,讓它們同時開始執行。
- 按順序回傳:返回一個特殊的迭代器(iterator)。當對這個迭代器進行迭代時,會按照提交任務的順序,等待並依序回傳每個任務的結果。
- GPT舉的例子是這樣,假設有三個任務:
- 任務A(3秒完成)
- 任務B(1秒完成)
- 任務C(2秒完成)
- 使用 as_completed(),會先拿到任務B的結果,然後是任務C,最後是任務A。但如果使用 map(),它會先等待任務A完成,然後返回其結果,接著等待任務B完成(已經因為concurrent的優勢完成了),確認返回其結果,以此類推任務C。
結論
如果要依照完成的順序性回傳結果的話使用submit()搭配as_complete(),要依照傳入的順序性回傳結果的話使用map(),兩者的程式碼依照GPT的舉例分別會像是以下:
- as_complete():
results = (future.result() for future in concurrent.futures.as_completed(futures))
- map():
results = executor.map(worker, items)