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. With ThreadPoolExecutor, 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 with statement, which will shutdown the Executor (waiting as if Executor.shutdown() were called with wait set to True):

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 multiprocessing start method (see コンテキストと開始方式) will change away from fork in Python 3.14. Code that requires fork be used for their ProcessPoolExecutor should explicitly specify that by passing a mp_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 を送出します。

set_exception(exception)

Future に関連付けられたワークの結果を Exception exception に設定します。

このメソッドは、 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.