concurrent.futures — 병렬 작업 실행하기¶
Added in version 3.2.
소스 코드: Lib/concurrent/futures/thread.py와 Lib/concurrent/futures/process.py
concurrent.futures 모듈은 비동기적으로 콜러블을 실행하는 고수준 인터페이스를 제공합니다.
비동기 실행은 (ThreadPoolExecutor를 사용해서) 스레드나 (ProcessPoolExecutor를 사용해서) 별도의 프로세스로 수행 할 수 있습니다. 둘 다 추상 Executor 클래스로 정의된 것과 같은 인터페이스를 구현합니다.
가용성: not Emscripten, not WASI.
This module does not work or is not available on WebAssembly platforms
wasm32-emscripten and wasm32-wasi. See
웹어셈블리 플랫폼 for more information.
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)과 비슷하지만, 다음과 같은 차이가 있습니다:- iterables 는 느긋하게 처리되는 것이 아니라 즉시 수집됩니다. 
- fn 는 비동기적으로 실행되며 fn 에 대한 여러 호출이 동시에 이루어질 수 있습니다. 
 - 반환된 이터레이터는 - __next__()가 호출되었을 때,- Executor.map()에 대한 최초 호출에서 timeout 초 후에도 결과를 사용할 수 없는 경우- TimeoutError를 발생시킵니다. timeout 은 int 또는 float가 될 수 있습니다. timeout 이 지정되지 않았거나- None인 경우, 대기 시간에는 제한이 없습니다.- fn 호출이 예외를 일으키면, 값을 이터레이터에서 꺼낼 때 해당 예외가 발생합니다. - ProcessPoolExecutor를 사용할 때, 이 메서드는 iterables 를 다수의 덩어리로 잘라서 별도의 작업으로 풀에 제출합니다. 이러한 덩어리의 (대략적인) 크기는 chunksize 를 양의 정수로 설정하여 지정할 수 있습니다. 매우 긴 이터러블의 경우 chunksize 에 큰 값을 사용하면 기본 크기인 1에 비해 성능이 크게 향상될 수 있습니다.- ThreadPoolExecutor의 경우, chunksize 는 아무런 효과가 없습니다.- 버전 3.5에서 변경: chunksize 인자가 추가되었습니다. 
 - shutdown(wait=True, *, cancel_futures=False)¶
- 현재 계류 중인 퓨처가 실행 완료될 때, 사용 중인 모든 자원을 해제해야 한다는 것을 실행기에 알립니다. 종료(shutdown) 후에 이루어지는 - Executor.submit()과- Executor.map()호출은- RuntimeError를 발생시킵니다.- wait 가 - True면, 계류 중인 모든 퓨처가 실행을 마치고 실행기와 관련된 자원이 해제될 때까지 이 메서드는 돌아오지 않습니다. wait 가- False면, 이 메서드는 즉시 돌아오고 실행기와 연관된 자원은 계류 중인 모든 퓨처가 실행을 마칠 때 해제됩니다. wait 의 값과 관계없이, 모든 계류 중인 퓨처가 실행을 마칠 때까지 전체 파이썬 프로그램이 종료되지 않습니다.- cancel_futures가 - True이면, 이 메서드는 실행기가 실행을 시작시키지 않은 계류 중인 모든 퓨처를 취소합니다. cancel_futures의 값과 관계없이 완료되었거나 실행 중인 퓨처는 취소되지 않습니다.- cancel_futures와 wait가 모두 - True이면, 이 메서드가 반환하기 전에 실행기가 실행을 시작한 모든 퓨처가 완료됩니다. 나머지 퓨처는 취소됩니다.- with문을 사용하여- Executor를 종료시키면 (- Executor.shutdown()를 wait 값- 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)
    # 작업자 스레드가 하나뿐인데, wait_on_future 를 실행하고 있으므로
    # f 는 완료되지 않습니다.
    print(f.result())
executor = ThreadPoolExecutor(max_workers=1)
executor.submit(wait_on_future)
- class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())¶
- 최대 max_workers 스레드의 풀을 사용하여 호출을 비동기적으로 실행하는 - Executor서브 클래스.- All threads enqueued to - ThreadPoolExecutorwill be joined before the interpreter can exit. Note that the exit handler which does this is executed before any exit handlers added using- atexit. This means exceptions in the main thread must be caught and handled in order to signal threads to exit gracefully. For this reason, it is recommended that- ThreadPoolExecutornot be used for long-running tasks.- initializer 는 각 작업자 스레드의 시작 부분에서 호출되는 선택적 콜러블입니다; initargs 는 initializer에 전달되는 인자들의 튜플입니다. initializer 가 예외를 발생시키는 경우, 현재 계류 중인 모든 작업과 풀에 추가로 작업을 제출하려는 시도는 - BrokenThreadPool을 발생시킵니다.- 버전 3.5에서 변경: max_workers 가 - None이거나 주어지지 않았다면, 기본값으로 기계의 프로세서 수에- 5를 곱한 값을 사용합니다.- ThreadPoolExecutor가 CPU 작업보다는 I/O를 동시에 진행하는데 자주 쓰이고, 작업자의 수가- ProcessPoolExecutor보다 많아야 한다고 가정하고 있습니다.- 버전 3.6에서 변경: 디버깅 편의를 위해 사용자가 풀이 만드는 작업자 스레드의 - threading.Thread이름을 제어 할 수 있도록, thread_name_prefix 매개 변수를 추가했습니다.- 버전 3.7에서 변경: initializer 및 initargs 인자가 추가되었습니다. - 버전 3.8에서 변경: max_workers의 기본값은 - min(32, os.cpu_count() + 4)로 변경됩니다. 이 기본값은 I/O 병목 작업을 위해 최소 5개의 작업자를 유지합니다. GIL을 반납하는 CPU 병목 작업을 위해 최대 32개의 CPU 코어를 사용합니다. 또한 많은 코어를 가진 시스템에서 매우 큰 자원을 묵시적으로 사용하는 것을 방지합니다.- ThreadPoolExecutor는 이제 max_workers 작업자 스레드를 시작하기 전에 유휴 작업자 스레드를 재사용합니다. 
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://nonexistant-subdomain.python.org/']
# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its 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 모듈을 사용합니다. 전역 인터프리터 록 을 피할 수 있도록 하지만, 오직 피클 가능한 객체만 실행되고 반환될 수 있음을 의미합니다.
__main__ 모듈은 작업자 서브 프로세스가 임포트 할 수 있어야 합니다. 즉, ProcessPoolExecutor 는 대화형 인터프리터에서 작동하지 않습니다.
ProcessPoolExecutor 에 제출된 콜러블에서 Executor 나 Future 메서드를 호출하면 교착 상태가 발생합니다.
- class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None)¶
- An - Executorsubclass that executes calls asynchronously using a pool of at most max_workers processes. If max_workers is- Noneor not given, it will default to the number of processors on the machine. If max_workers is less than or equal to- 0, then a- ValueErrorwill be raised. On Windows, max_workers must be less than or equal to- 61. If it is not then- ValueErrorwill be raised. If max_workers is- None, then the default chosen will be at most- 61, even if more processors are available. mp_context can be a- multiprocessingcontext or- None. It will be used to launch the workers. If mp_context is- Noneor not given, the default- multiprocessingcontext is used. See 컨텍스트 및 시작 방법.- initializer 는 각 작업자 프로세스의 시작 부분에서 호출되는 선택적 콜러블입니다; initargs 는 initializer에 전달되는 인자들의 튜플입니다. initializer 가 예외를 발생시키는 경우, 현재 계류 중인 모든 작업과 풀에 추가로 작업을 제출하려는 시도는 - BrokenProcessPool을 발생시킵니다.- max_tasks_per_child is an optional argument that specifies the maximum number of tasks a single process can execute before it will exit and be replaced with a fresh worker process. By default max_tasks_per_child is - Nonewhich means worker processes will live as long as the pool. When a max is specified, the “spawn” multiprocessing start method will be used by default in absence of a mp_context parameter. This feature is incompatible with the “fork” start method.- 버전 3.3에서 변경: 작업자 프로세스 중 하나가 갑자기 종료되면, - BrokenProcessPool오류가 발생합니다. 이전에는, 동작이 정의되지 않았지만, 실행기나 그 퓨처에 대한 연산이 종종 멈추거나 교착 상태에 빠졌습니다.- 버전 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 their- ProcessPoolExecutorshould explicitly specify that by passing a- mp_context=multiprocessing.get_context("fork")parameter.- 버전 3.11에서 변경: max_tasks_per_child 인자가 추가되어 사용자가 풀에 있는 작업자의 수명을 제어 할 수 있습니다. - 버전 3.12에서 변경: On POSIX systems, if your application has multiple threads and the - multiprocessingcontext uses the- "fork"start method: The- os.fork()function called internally to spawn workers may raise a- DeprecationWarning. Pass a mp_context configured to use a different start method. See the- os.fork()documentation for further explanation.
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인 경우, 대기 시간에는 제한이 없습니다.- 완료하기 전에 퓨처가 취소되면 - CancelledError가 발생합니다.- 호출이 예외를 일으키는 경우, 이 메서드는 같은 예외를 발생시킵니다. 
 - exception(timeout=None)¶
- 호출이 일으킨 예외를 돌려줍니다. 호출이 아직 완료되지 않는 경우, 이 메서드는 timeout 초까지 대기합니다. timeout 초 내에 호출이 완료되지 않으면 - TimeoutError가 발생합니다. timeout 은 int 또는 float가 될 수 있습니다. timeout 이 지정되지 않았거나- None인 경우, 대기 시간에는 제한이 없습니다.- 완료하기 전에 퓨처가 취소되면 - CancelledError가 발생합니다.- 호출이 예외 없이 완료되면, - None이 반환됩니다.
 - add_done_callback(fn)¶
- 콜러블 fn 을 퓨처에 연결합니다. fn 은 퓨처가 취소되거나 실행이 종료될 때 퓨처를 유일한 인자로 호출됩니다. - 추가된 콜러블은 추가된 순서대로 호출되며, 항상 콜러블을 추가한 프로세스에 속하는 스레드에서 호출됩니다. 콜러블이 - Exception서브 클래스를 발생시키면, 로그 되고 무시됩니다. 콜러블이- BaseException서브 클래스를 발생시키면, 동작은 정의되지 않습니다.- 퓨처가 이미 완료되었거나 취소된 경우 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 로 주어진 여러 (서로 다른 - Executor인스턴스가 만든 것들도 가능합니다)- Future인스턴스들이 완료할 때까지 기다립니다. fs 로 주어진 중복 퓨처는 제거되고 한 번만 반환됩니다. 집합들의 이름있는 2-튜플을 돌려줍니다.- done이라는 이름의 첫 번째 집합은 대기가 끝나기 전에 완료된 (끝났거나 취소된) 퓨처를 담고 있습니다.- not_done이라는 이름의 두 번째 집합은 완료되지 않은 (계류 중이거나 실행 중인) 퓨처를 담고 있습니다.- timeout 은 반환하기 전에 대기 할 최대 시간(초)을 제어하는 데 사용할 수 있습니다. timeout 은 int 또는 float가 될 수 있습니다. 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 로 주어진 여러 (서로 다른 - Executor인스턴스가 만든 것들도 가능합니다) 퓨처들이 완료되는 대로 (끝났거나 취소된 퓨처) 일드 하는- Future인스턴스의 이터레이터를 반환합니다. fs 에 중복된 퓨처가 들어있으면 한 번만 반환됩니다.- as_completed()가 호출되기 전에 완료한 모든 퓨처들이 먼저 일드 됩니다. 반환된 이터레이터는,- __next__()가 호출되고,- as_completed()호출 시점으로부터 timeout 초 후에 결과를 얻을 수 없는 경우- TimeoutError를 발생시킵니다. timeout 은 int 또는 float가 될 수 있습니다. timeout 이 지정되지 않았거나- None인 경우, 대기 시간에는 제한이 없습니다.
더 보기
- PEP 3148 – 퓨처 - 계산을 비동기적으로 실행
- 파이썬 표준 라이브러리에 포함하기 위해, 이 기능을 설명한 제안. 
예외 클래스¶
- exception concurrent.futures.CancelledError¶
- 퓨처가 취소될 때 발생합니다. 
- exception concurrent.futures.TimeoutError¶
- TimeoutError의 폐지된 별칭, 퓨처 연산이 지정된 시간제한을 초과할 때 발생합니다.- 버전 3.11에서 변경: This class was made an alias of - TimeoutError.
- exception concurrent.futures.BrokenExecutor¶
- RuntimeError에서 파생됩니다, 이 예외 클래스는 어떤 이유로 실행기가 망가져서 새 작업을 제출하거나 실행할 수 없을 때 발생합니다.- 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.