ThreadPoolExecutor
タスクを並行して実行します
「ThreadPoolExecutor」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。
スレッドプールを使う理由
スレッドの作成と結合を手動で行うのは面倒です。concurrent.futures.ThreadPoolExecutorを使うと、ワーカースレッドのプールを管理し、結果を簡単に受け取れます。
from concurrent.futures import ThreadPoolExecutor
def square(n):
return n * n
with ThreadPoolExecutor() as ex:
future = ex.submit(square, 5)
print(future.result())submitとFuture
submit()は呼び出しをスケジュールし、すぐにFutureを返します。値を取得するには.result()を呼び出します。値の準備ができるまで、この呼び出しはブロックします。
from concurrent.futures import ThreadPoolExecutor
def greet(name):
return 'hi ' + name
with ThreadPoolExecutor(max_workers=2) as ex:
f1 = ex.submit(greet, 'Ana')
f2 = ex.submit(greet, 'Bob')
print(f1.result())
print(f2.result())複数の入力に対するmap
executor.map(func, iterable)は、すべての項目に対して関数を並行して実行し、結果を入力順に生成します。
from concurrent.futures import ThreadPoolExecutor
def cube(n):
return n ** 3
with ThreadPoolExecutor() as ex:
results = ex.map(cube, range(5))
print(list(results))ワーカー数を制御する
max_workersは、一度に実行できるスレッド数の上限を設定します。I/Oバウンドな処理では、CPUコア数より多くのワーカーを使用できます。
from concurrent.futures import ThreadPoolExecutor
import time
def io_task(n):
time.sleep(0.05)
return n
start = time.perf_counter()
with ThreadPoolExecutor(max_workers=4) as ex:
print(list(ex.map(io_task, range(4))))
print('ran concurrently')as_completed
as_completed(futures)は、投入された順序に関係なく、各Futureが完了した時点ですぐに生成します。結果を到着次第処理したい場合に便利です。
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
def work(n):
time.sleep(0.01 * (3 - n))
return n
with ThreadPoolExecutor() as ex:
futures = [ex.submit(work, i) for i in range(3)]
for f in as_completed(futures):
print('finished', f.result())例外を処理する
タスクで例外が発生すると、その例外はFutureに保存され、.result()を呼び出したときに再発生します。その呼び出しをtry/exceptで囲みます。
from concurrent.futures import ThreadPoolExecutor
def risky(n):
if n == 0:
raise ValueError('cannot be zero')
return 10 // n
with ThreadPoolExecutor() as ex:
f = ex.submit(risky, 0)
try:
print(f.result())
except ValueError as e:
print('caught:', e)複数の引数を使ったマッピング
mapは複数のイテラブルを受け取り、組み込み関数のmapと同じように、それらを引数として組み合わせます。
from concurrent.futures import ThreadPoolExecutor
def add(a, b):
return a + b
with ThreadPoolExecutor() as ex:
print(list(ex.map(add, [1, 2, 3], [10, 20, 30])))結果を辞書に収集する
as_completedを使う場合、どの結果がどの入力に対応するか分かるように、各Futureを入力に対応付けるのが一般的です。
from concurrent.futures import ThreadPoolExecutor, as_completed
def length(word):
return len(word)
words = ['cat', 'tiger', 'ox']
with ThreadPoolExecutor() as ex:
future_to_word = {ex.submit(length, w): w for w in words}
out = {}
for f in as_completed(future_to_word):
out[future_to_word[f]] = f.result()
print(sorted(out.items()))コンテキストマネージャーによる終了処理
executorをwithブロックで使用すると、shutdown()が自動的に呼び出され、保留中のすべてのタスクが完了するまで待機します。
from concurrent.futures import ThreadPoolExecutor
def job(n):
return n * 2
with ThreadPoolExecutor() as ex:
futures = [ex.submit(job, i) for i in range(3)]
print('all tasks done after the with block')
print([f.result() for f in futures])Futureの状態を確認する
Futureには.done()と.running()があり、ブロックせずに進行状況を確認できます。
from concurrent.futures import ThreadPoolExecutor
def quick(n):
return n + 1
with ThreadPoolExecutor() as ex:
f = ex.submit(quick, 41)
result = f.result()
print('done?', f.done())
print('value:', result)使用する場面
ThreadPoolExecutorは、HTTP呼び出し、ファイル読み取り、データベースクエリなど、多数の小さなI/Oバウンドタスクに適しています。CPUバウンドな処理には、代わりにProcessPoolExecutorを使用します。
from concurrent.futures import ThreadPoolExecutor
urls = ['a', 'b', 'c']
def fetch(u):
return 'fetched ' + u
with ThreadPoolExecutor(max_workers=3) as ex:
for r in ex.map(fetch, urls):
print(r)理解度チェック
ThreadPoolExecutorの理解度を確認しましょう。
復習
ThreadPoolExecutorについて学びました。
submit()はFutureを返し、map()はイテラブルを順番に処理します。as_completed()は処理が完了した順にfutureを返します。- 例外は
result()を通じて発生します。 withブロックがシャットダウンを処理します。
次は、multiprocessingによる真の並列処理です。
よくある質問
「ThreadPoolExecutor」レッスンは無料ですか?
はい。「ThreadPoolExecutor」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。
「ThreadPoolExecutor」で何を学びますか?
タスクを並行して実行します ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Python Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「ThreadPoolExecutor」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPython Academyレッスンでコードを書いて実行できますか?
はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- スレッドとGIL
- ThreadPoolExecutor
- multiprocessingの基礎
- データの安全な共有