concurrent.futures --- 並列タスク実行¶
Added in version 3.2.
Source code: Lib/concurrent/futures/thread.py and Lib/concurrent/futures/process.py
concurrent.futures モジュールは、非同期に実行できる呼び出し可能オブジェクトの高水準のインターフェースを提供します。
The asynchronous execution can be performed with threads, using
ThreadPoolExecutor, or separate processes, using
ProcessPoolExecutor. Both implement the same interface, which is
defined by the abstract Executor class.
concurrent.futures.Future must not be confused with
asyncio.Future, which is designed for use with asyncio
tasks and coroutines. See the asyncio's Future
documentation for a detailed comparison of the two.
利用可能な環境: not WASI.
このモジュールは WebAssembly では動作しないか、利用不可です。詳しくは、WebAssembly プラットフォーム を見てください。
Executor オブジェクト¶
- class concurrent.futures.Executor¶
非同期呼び出しを実行するためのメソッドを提供する抽象クラスです。このクラスを直接使ってはならず、具象サブクラスを介して使います。
- submit(fn, /, *args, **kwargs)¶
呼び出し可能オブジェクト fn を、
fn(*args, **kwargs)として実行するようにスケジュールし、呼び出し可能オブジェクトの実行を表現するFutureオブジェクトを返します。with ThreadPoolExecutor(max_workers=1) as executor: future = executor.submit(pow, 323, 1235) print(future.result())
- map(fn, *iterables, timeout=None, chunksize=1)¶
map(fn, *iterables)と似ていますが、次の違いがあります:the iterables are collected immediately rather than lazily;
fn は非同期に実行され、複数の fn の呼び出しが並行して行われる場合があります。
もし
__next__()が呼ばれその結果が元々のExecutor.map()の呼び出しから timeout 秒経った後も利用できない場合、返されるイテレータはTimeoutErrorを送出します。 timeout は整数または浮動小数点数です。 timeout を省略するかNoneを指定した場合、待ち時間に制限はありません。もし fn の呼び出しが例外を送出した場合、その例外はイテレータから値を受け取る時に送出されます。
When using
ProcessPoolExecutor, this method chops iterables into a number of chunks which it submits to the pool as separate tasks. The (approximate) size of these chunks can be specified by setting chunksize to a positive integer. For very long iterables, using a large value for chunksize can significantly improve performance compared to the default size of 1. WithThreadPoolExecutor, chunksize has no effect.バージョン 3.5 で変更: Added the chunksize argument.
- shutdown(wait=True, *, cancel_futures=False)¶
executor に対して、現在保留中のフューチャーが実行された後で、使用中のすべての資源を解放するように伝えます。シャットダウンにより後に
Executor.submit()とExecutor.map()を呼び出すとRuntimeErrorが送出されます。wait が
Trueの場合、すべての未完了のフューチャの実行が完了して Executor に関連付けられたリソースが解放されるまで、このメソッドは返りません。 wait がFalseの場合、このメソッドはすぐに返り、すべての未完了のフューチャの実行が完了したときに、 Executor に関連付けられたリソースが解放されます。 wait の値に関係なく、すべての未完了のフューチャの実行が完了するまで Python プログラム全体は終了しません。cancel_futures が
Trueの場合、このメソッドは executor がまだ実行を開始していない未完了のフューチャをすべてキャンセルします。 すでに完了したフューチャや実行中のフューチャは、cancel_futures の値にかかわらずキャンセルされません。cancel_futures と wait がともに
Trueの場合、executor が実行を開始したフューチャはすべて、このメソッドが返る前に完了します。 残りのフューチャはキャンセルされます。You can avoid having to call this method explicitly if you use the executor as a context manager via the
withstatement, which will shutdown theExecutor(waiting as ifExecutor.shutdown()were called with wait set toTrue):import shutil with ThreadPoolExecutor(max_workers=4) as e: e.submit(shutil.copy, 'src1.txt', 'dest1.txt') e.submit(shutil.copy, 'src2.txt', 'dest2.txt') e.submit(shutil.copy, 'src3.txt', 'dest3.txt') e.submit(shutil.copy, 'src4.txt', 'dest4.txt')
バージョン 3.9 で変更: cancel_futures が追加されました。
ThreadPoolExecutor¶
ThreadPoolExecutor はスレッドのプールを使用して非同期に呼び出しを行う、 Executor のサブクラスです。
Future に関連づけられた呼び出し可能オブジェクトが、別の Future の結果を待つ時にデッドロックすることがあります。例:
import time
def wait_on_b():
time.sleep(5)
print(b.result()) # b は a を待っているため完了しない
return 5
def wait_on_a():
time.sleep(5)
print(a.result()) # a は b を待っているため完了しない
return 6
executor = ThreadPoolExecutor(max_workers=2)
a = executor.submit(wait_on_b)
b = executor.submit(wait_on_a)
以下でも同様です:
def wait_on_future():
f = executor.submit(pow, 5, 2)
# This will never complete because there is only one worker thread and
# it is executing this function.
print(f.result())
executor = ThreadPoolExecutor(max_workers=1)
future = executor.submit(wait_on_future)
# Note: calling future.result() would also cause a deadlock because
# the single worker thread is already waiting for wait_on_future().
- class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())¶
最大で max_workers 個のスレッドを非同期実行に使う
Executorのサブクラスです。ThreadPoolExecutorに登録されたすべてのスレッドは、インタープリタの終了前に join されます。 この処理を行う終了ハンドラは、atexitで追加した終了ハンドラよりも 前に 実行されることに注意してください。 そのため、スレッドに正常終了を指示できるように、メインスレッドの例外を捕捉して処理しなければなりません。 この理由から、長時間実行するタスクにはThreadPoolExecutorを使わないことを推奨します。initializer は省略可能な呼び出し可能オブジェクトで、各ワーカースレッドの開始時に呼び出されます。 initargs は、この初期化処理に渡す引数のタプルです。 initializer が例外を送出した場合、現在未完了のジョブはすべて
BrokenThreadPoolを送出し、プールへの新たなジョブの投入も同じ例外を送出します。バージョン 3.5 で変更: max_workers が
Noneか指定されない場合のデフォルト値はマシンのプロセッサの数に 5 を掛けたものになります。これは、ThreadPoolExecutorは CPU の処理ではなく I/O をオーバーラップするのによく使用されるため、ProcessPoolExecutorのワーカーの数よりもこのワーカーの数を増やすべきであるという想定に基づいています。バージョン 3.6 で変更: thread_name_prefix 引数が追加され、デバッグしやすくなるようにプールから作られたワーカスレッド
threading.Threadの名前を管理できるようになりました。バージョン 3.7 で変更: initializer と initargs 引数が追加されました。
バージョン 3.8 で変更: max_workers のデフォルト値が
min(32, os.cpu_count() + 4)に変更されました。 このデフォルト値により、I/O バウンドのタスクには少なくとも 5 個のワーカーが確保されます。 GIL を解放する CPU バウンドのタスクには最大 32 個の CPU コアを利用します。 また、多数のコアを持つマシンで暗黙に大量のリソースを使うことを避けられます。ThreadPoolExecutor は、max_workers 個のワーカースレッドを起動する前に、待機中のワーカースレッドを再利用するようにもなりました。
バージョン 3.13 で変更: max_workers のデフォルト値が
min(32, (os.process_cpu_count() or 1) + 4)に変更されました。
ThreadPoolExecutor の例¶
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://nonexistent-subdomain.python.org/']
# 一つのページを取得し、URL と内容を報告する
def load_url(url, timeout):
with urllib.request.urlopen(url, timeout=timeout) as conn:
return conn.read()
# with 文を使えばスレッドを速やかに後始末できる
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# 読み込みを開始し、各フューチャに URL を対応付ける
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
ProcessPoolExecutor¶
ProcessPoolExecutor はプロセスプールを使って非同期呼び出しを実施する Executor のサブクラスです。ProcessPoolExecutor は multiprocessing モジュールを利用します。このため Global Interpreter Lock を回避することができますが、pickle 化できるオブジェクトしか実行したり返したりすることができません。
__main__ モジュールはワーカサブプロセスでインポート可能でなければなりません。
すなわち、 ProcessPoolExecutor は対話的インタープリタでは動きません。
ProcessPoolExecutor に渡された呼び出し可能オブジェクトから Executor や Future メソッドを呼ぶとデッドロックに陥ります。
Note that the restrictions on functions and arguments needing to picklable as
per multiprocessing.Process apply when using submit()
and map() on a ProcessPoolExecutor. A function defined
in a REPL or a lambda should not be expected to work.
- class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None)¶
最大 max_workers 個のプロセスからなるプールを使い、呼び出しを非同期に実行する
Executorのサブクラスです。 max_workers がNoneまたは省略された場合、デフォルトでos.process_cpu_count()が使われます。 max_workers が0以下の場合はValueErrorを送出します。 Windows では、max_workers は61以下でなければなりません。 そうでない場合はValueErrorを送出します。 max_workers がNoneの場合、利用可能なプロセッサ数がそれより多くても、デフォルトで選択される値は最大61です。 mp_context にはmultiprocessingのコンテキストまたはNoneを指定でき、ワーカーの起動に使われます。 mp_context がNoneまたは省略された場合、デフォルトのmultiprocessingコンテキストが使われます。 コンテキストと開始方式 を参照してください。initializer は省略可能な呼び出し可能オブジェクトで、各ワーカープロセスの開始時に呼び出されます。 initargs は、この初期化処理に渡す引数のタプルです。 initializer が例外を送出した場合、現在未完了のジョブはすべて
BrokenProcessPoolを送出し、プールへの新たなジョブの投入も同じ例外を送出します。max_tasks_per_child は省略可能な引数で、一つのプロセスが終了して新しいワーカープロセスに置き換わるまでに実行できるタスクの最大数を指定します。 デフォルトの max_tasks_per_child は
Noneで、ワーカープロセスはプールが存在する限り存続します。 最大数を指定し、mp_context パラメータを指定しなかった場合、デフォルトでは multiprocessing の開始方式に "spawn" が使われます。 この機能は "fork" 開始方式とは併用できません。バージョン 3.3 で変更: ワーカプロセスの1つが突然終了した場合、
BrokenProcessPoolエラーが送出されるようになりました。 以前は挙動は未定義でしたが、 executor や futures がフリーズしたりデッドロックを起こすことがしばしばでした。バージョン 3.7 で変更: プールが作成するワーカープロセスの開始方式を利用者が制御できるよう、mp_context 引数が追加されました。
initializer と initargs 引数が追加されました。
注釈
The default
multiprocessingstart method (see コンテキストと開始方式) will change away from fork in Python 3.14. Code that requires fork be used for theirProcessPoolExecutorshould explicitly specify that by passing amp_context=multiprocessing.get_context("fork")parameter.バージョン 3.11 で変更: プール内のワーカーの存続期間を利用者が制御できるよう、max_tasks_per_child 引数が追加されました。
バージョン 3.12 で変更: POSIX システムで、アプリケーションが複数のスレッドを持ち、
multiprocessingコンテキストが"fork"開始方式を使う場合、ワーカーを起動するために内部で呼び出すos.fork()関数がDeprecationWarningを送出することがあります。 別の開始方式を使うように設定した mp_context を渡してください。 詳しくはos.fork()のドキュメントを参照してください。バージョン 3.13 で変更: max_workers のデフォルトで、
os.cpu_count()の代わりにos.process_cpu_count()を使うようになりました。バージョン 3.13.15 で変更: Fixed a deadlock (gh-115634) where the executor could hang after a worker process exited upon reaching its max_tasks_per_child limit while tasks remained queued.
ProcessPoolExecutor の例¶
import concurrent.futures
import math
PRIMES = [
112272535095293,
112582705942171,
112272535095293,
115280095190773,
115797848077099,
1099726899285419]
def is_prime(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:
return False
return True
def main():
with concurrent.futures.ProcessPoolExecutor() as executor:
for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
print('%d is prime: %s' % (number, prime))
if __name__ == '__main__':
main()
Future オブジェクト¶
Future クラスは呼び出し可能オブジェクトの非同期実行をカプセル化します。 Future のインスタンスは Executor.submit() によって生成されます。
- class concurrent.futures.Future¶
呼び出し可能オブジェクトの非同期実行をカプセル化します。
FutureインスタンスはExecutor.submit()で生成され、テストを除いて直接生成すべきではありません。- cancel()¶
呼び出しのキャンセルを試みます。 呼び出しがすでに実行中または実行済みで、キャンセルできない場合は
Falseを返します。 それ以外の場合は呼び出しをキャンセルしてTrueを返します。
- cancelled()¶
呼び出しが正常にキャンセルされた場合
Trueを返します。
- running()¶
現在呼び出しが実行中でキャンセルできない場合
Trueを返します。
- done()¶
呼び出しが正常にキャンセルされたか終了した場合
Trueを返します。
- result(timeout=None)¶
呼び出しによって返された値を返します。もし呼び出しがまだ完了していなければ、このメソッドは timeout 秒の間、待機します。もし呼び出しが timeout 秒間の間に完了しなければ、
TimeoutErrorが送出されます。 timeout はintかfloatを指定できます。もし timeout が指定されていないか、Noneであれば、待機時間に制限はありません。future が完了する前にキャンセルされた場合
CancelledErrorが送出されます。呼び出しが例外を送出した場合、このメソッドも同じ例外を送出します。
- exception(timeout=None)¶
呼び出しによって送出された例外を返します。もし呼び出しがまだ完了されていなければ、このメソッドは timeout 秒だけ待機します。もし呼び出しが timeout 秒の間に完了しなければ、
TimeoutErrorが送出されます。 timeout にはintかfloatを指定できます。 timeout が指定されていないか、Noneであれば、待機時間に制限はありません。future が完了する前にキャンセルされた場合
CancelledErrorが送出されます。呼び出しが例外を送出することなく完了した場合、
Noneを返します。
- add_done_callback(fn)¶
呼び出し可能な fn オブジェクトを future にアタッチします。futureがキャンセルされたか、実行を終了した際に、future をそのただ一つの引数として fn が呼び出されます。
追加された呼び出し可能オブジェクトは、追加された順番で呼びだされ、追加を行ったプロセスに属するスレッド中で呼び出されます。もし呼び出し可能オブジェクトが
Exceptionのサブクラスを送出した場合、それはログに記録され無視されます。呼び出し可能オブジェクトがBaseExceptionのサブクラスを送出した場合の動作は未定義です。もしfutureがすでに完了しているか、キャンセル済みであれば、fn は即座に実行されます。
以下の
Futureメソッドは、ユニットテストでの使用とExecutorを実装することを意図しています。- set_running_or_notify_cancel()¶
このメソッドを呼び出してよいのは、
Futureに関連付けられた処理を実行する前のExecutorの実装と、ユニットテストだけです。このメソッドが
Falseを返す場合、Futureはキャンセルされています。つまり、Future.cancel()が呼び出されてTrueが返っています。Futureの完了を (as_completed()またはwait()により) 待機するすべてのスレッドが起動します。このメソッドが
Trueを返す場合、Futureはキャンセルされておらず、実行状態に移行しています。 つまり、Future.running()を呼び出すとTrueが返ります。このメソッドは一度だけ呼び出すことができ、
Future.set_result()またはFuture.set_exception()が呼び出された後には呼び出すことができません。
- set_result(result)¶
Futureに関連付けられたワークの結果を result に設定します。このメソッドは、
Executorの実装またはユニットテストによってのみ使用してください。バージョン 3.8 で変更:
Futureがすでに完了している場合、このメソッドはconcurrent.futures.InvalidStateErrorを送出します。
モジュール関数¶
- concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)¶
fs で指定された
Futureインスタンス (異なるExecutorインスタンスで作成されたものでも可) が完了するまで待機します。 fs に重複して指定されたフューチャは一つにまとめられ、一度だけ返されます。 集合を要素とする、要素数 2 の名前付きタプルを返します。 最初の集合doneには、待機が終わるまでに完了したフューチャ (実行済みまたはキャンセル済みのフューチャ) が含まれます。 二つ目の集合not_doneには、完了していないフューチャ (保留中または実行中のフューチャ) が含まれます。timeout で結果を返すまで待機する最大秒数を指定できます。timeout は整数か浮動小数点数をとります。timeout が指定されないか
Noneの場合、無期限に待機します。return_when でこの関数がいつ結果を返すか指定します。指定できる値は以下の 定数のどれか一つです:
定数
説明
- concurrent.futures.FIRST_COMPLETED¶
いずれかのフューチャが終了したかキャンセルされたときに返します。
- concurrent.futures.FIRST_EXCEPTION¶
いずれかのフューチャが例外を送出して終了すると、この関数は返ります。 例外を送出するフューチャがない場合は、
ALL_COMPLETEDと等価です。- concurrent.futures.ALL_COMPLETED¶
すべてのフューチャが終了したかキャンセルされたときに返します。
- concurrent.futures.as_completed(fs, timeout=None)¶
fs で指定された
Futureインスタンス (異なるExecutorインスタンスで作成されたものでも可) を、完了するたびに (実行済みまたはキャンセル済みになった順に) yield するイテレータを返します。 fs に重複して指定されたフューチャは、一度だけ返されます。as_completed()の呼び出し前に完了していたフューチャが、最初に yield されます。 返されたイテレータの__next__()が呼び出された際、最初のas_completed()の呼び出しから timeout 秒が経過しても結果を取得できなければ、TimeoutErrorを送出します。 timeout には整数または浮動小数点数を指定できます。 timeout が省略された場合やNoneの場合は、待ち時間に制限はありません。
参考
- PEP 3148 -- futures - execute computations asynchronously
この機能を Python 標準ライブラリに含めることを述べた提案です。
例外クラス¶
- exception concurrent.futures.CancelledError¶
future がキャンセルされたときに送出されます。
- exception concurrent.futures.TimeoutError¶
TimeoutErrorの非推奨のエイリアスです。 フューチャの操作が指定されたタイムアウトを超えた場合に送出されます。バージョン 3.11 で変更: このクラスは
TimeoutErrorのエイリアスになりました。
- exception concurrent.futures.BrokenExecutor¶
RuntimeErrorの派生クラスです。 何らかの理由で executor が壊れて、新しいタスクの投入や実行に使えなくなった場合に送出されます。Added in version 3.7.
- exception concurrent.futures.InvalidStateError¶
フューチャに対して、現在の状態では許可されていない操作を行った場合に送出されます。
Added in version 3.8.
- exception concurrent.futures.thread.BrokenThreadPool¶
BrokenExecutorの派生クラスです。ThreadPoolExecutorのワーカーのいずれかで初期化に失敗した場合に送出されます。Added in version 3.7.
- exception concurrent.futures.process.BrokenProcessPool¶
BrokenExecutor(以前はRuntimeError) の派生クラスです。ProcessPoolExecutorのワーカーのいずれかが正常でない形で終了した場合 (例えば、外部から強制終了された場合) に送出されます。Added in version 3.3.