Документация Python неофициальный перевод

concurrent.futures.md

432 строк · 52.7 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.16/library/concurrent.futures.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `concurrent.futures` – Запуск параллельных задач89Добавлено в версии 3.2.1011**Исходный код:** [Lib/concurrent/futures/thread.py](https://python-all.ru/src/main/Lib/concurrent/futures/thread.py), [Lib/concurrent/futures/process.py](https://python-all.ru/src/main/Lib/concurrent/futures/process.py), и [Lib/concurrent/futures/interpreter.py](https://python-all.ru/src/main/Lib/concurrent/futures/interpreter.py)1213---1415Модуль `concurrent.futures` предоставляет высокоуровневый интерфейс для асинхронного выполнения вызываемых объектов.1617Асинхронное выполнение может осуществляться с помощью потоков, используя [`ThreadPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) или [`InterpreterPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.InterpreterPoolExecutor), или отдельных процессов, используя [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor). Каждый реализует один и тот же интерфейс, который определён абстрактным классом [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor).1819[`concurrent.futures.Future`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future) не следует путать с [`asyncio.Future`](https://python-all.ru/3.16/library/asyncio-future.html#asyncio.Future), который предназначен для использования с [`asyncio`](https://python-all.ru/3.16/library/asyncio.html#module-asyncio) задачами и корутинами. Обратитесь к документации [asyncio.Future](https://python-all.ru/3.16/library/asyncio-future.html) для подробного сравнения двух.2021[Доступность](https://python-all.ru/3.16/library/intro.html#availability): не WASI.2223Этот модуль не работает или недоступен на WebAssembly. Подробнее см. [платформы WebAssembly](https://python-all.ru/3.16/library/intro.html#wasm-availability).2425## Объекты исполнителя2627#### `class concurrent.futures.Executor`2829Абстрактный класс, предоставляющий методы для асинхронного выполнения вызовов. Его не следует использовать напрямую, а через его конкретные подклассы.3031#### `submit(fn, /, *args, **kwargs)`3233Планирует выполнение вызываемого объекта *fn* как `fn(*args, **kwargs)` и возвращает объект [`Future`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future), представляющий выполнение вызываемого объекта.3435```python36with ThreadPoolExecutor(max_workers=1) as executor:37    future = executor.submit(pow, 323, 1235)38    print(future.result())39```4041#### `map(fn, *iterables, timeout=None, chunksize=1, buffersize=None)`4243Аналогично [`map(fn, *iterables)`](https://python-all.ru/3.16/library/functions.html#map), но:4445- *iterables* собираются сразу, а не лениво, если только не указан *buffersize*, ограничивающий количество отправленных задач, результаты которых ещё не получены. Если буфер заполнен, итерация по *iterables* приостанавливается, пока результат не будет получен из буфера.46- *fn* выполняется асинхронно, и несколько вызовов *fn* могут выполняться одновременно.4748Возвращаемый итератор возбуждает [`TimeoutError`](https://python-all.ru/3.16/library/exceptions.html#TimeoutError), если вызван [`__next__()`](https://python-all.ru/3.16/library/stdtypes.html#iterator.__next__) и результат недоступен через *timeout* секунд после исходного вызова `Executor.map()`. *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или равен `None`, время ожидания не ограничено.4950Если вызов *fn* возбуждает исключение, то это исключение будет возбуждено при получении его значения из итератора.5152При использовании [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) этот метод разбивает *iterables* на несколько блоков, которые отправляет в пул как отдельные задачи. (Приблизительный) размер этих блоков можно задать, установив *chunksize* в положительное целое число. Для очень длинных итераций использование большого значения *chunksize* может значительно улучшить производительность по сравнению со значением по умолчанию, равным 1. Для [`ThreadPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) и [`InterpreterPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.InterpreterPoolExecutor) *chunksize* не влияет.5354Изменено в версии 3.5: Добавлен параметр *chunksize*.5556Изменено в версии 3.14: Добавлен параметр *buffersize*.5758#### `shutdown(wait=True, *, cancel_futures=False)`5960Сообщает исполнителю, что он должен освободить все используемые ресурсы, когда текущие ожидающие future завершат выполнение. Вызовы [`Executor.submit()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.submit) и [`Executor.map()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.map) после shutdown приведут к возбуждению [`RuntimeError`](https://python-all.ru/3.16/library/exceptions.html#RuntimeError).6162Если *wait* равен `True`, то этот метод не вернёт управление, пока все ожидающие future не завершат выполнение и ресурсы, связанные с исполнителем, не будут освобождены. Если *wait* равен `False`, то метод вернёт управление немедленно, а ресурсы, связанные с исполнителем, будут освобождены, когда все ожидающие future завершат выполнение. Независимо от значения *wait*, вся программа Python не завершится, пока все ожидающие future не завершат выполнение.6364Если *cancel\_futures* равен `True`, этот метод отменит все ожидающие future, которые исполнитель ещё не начал выполнять. Любые future, которые уже завершены или выполняются, отменены не будут, независимо от значения *cancel\_futures*.6566Если и *cancel\_futures*, и *wait* равны `True`, то все future, которые исполнитель начал выполнять, будут завершены до возврата из этого метода. Остальные future отменяются.6768Можно избежать явного вызова этого метода, если использовать исполнитель как [менеджер контекста](https://python-all.ru/3.16/glossary.html#term-context-manager) через оператор [`with`](https://python-all.ru/3.16/reference/compound_stmts.html#with), который завершит работу `Executor` (ожидая, как если бы `Executor.shutdown()` был вызван с *wait*, установленным в `True`):6970```python71import shutil72with ThreadPoolExecutor(max_workers=4) as e:73    e.submit(shutil.copy, 'src1.txt', 'dest1.txt')74    e.submit(shutil.copy, 'src2.txt', 'dest2.txt')75    e.submit(shutil.copy, 'src3.txt', 'dest3.txt')76    e.submit(shutil.copy, 'src4.txt', 'dest4.txt')77```7879Изменено в версии 3.9: Добавлен *cancel\_futures*.8081## ThreadPoolExecutor8283[`ThreadPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) – подкласс [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor), использующий пул потоков для асинхронного выполнения вызовов.8485Взаимоблокировки могут возникать, когда вызываемый объект, связанный с [`Future`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future), ожидает результаты другого `Future`. Например:8687```python88import time89def wait_on_b():90    time.sleep(5)91    print(b.result())  # b никогда не завершится, потому что он ожидает a.92    return 59394def wait_on_a():95    time.sleep(5)96    print(a.result())  # a никогда не завершится, потому что он ожидает b.97    return 69899executor = ThreadPoolExecutor(max_workers=2)100a = executor.submit(wait_on_b)101b = executor.submit(wait_on_a)102```103104И:105106```python107def wait_on_future():108    f = executor.submit(pow, 5, 2)109    # Это никогда не завершится, потому что есть только один рабочий поток и110    # он выполняет эту функцию.111    print(f.result())112113executor = ThreadPoolExecutor(max_workers=1)114future = executor.submit(wait_on_future)115# Примечание: вызов future.result() также приведёт к взаимоблокировке, потому что116# единственный рабочий поток уже ожидает wait_on_future().117```118119#### `class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())`120121Подкласс [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor), который использует пул не более чем из *max\_workers* потоков для асинхронного выполнения вызовов.122123Все потоки, поставленные в очередь `ThreadPoolExecutor`, будут присоединены до того, как интерпретатор сможет завершиться. Обратите внимание, что обработчик выхода, который это делает, выполняется *до* любых обработчиков выхода, добавленных с помощью `atexit`. Это означает, что исключения в главном потоке должны быть перехвачены и обработаны, чтобы потоки могли корректно завершиться. По этой причине рекомендуется не использовать `ThreadPoolExecutor` для долго выполняющихся задач.124125*initializer* – это необязательный вызываемый объект, который вызывается в начале каждого рабочего потока; *initargs* – это кортеж аргументов, передаваемых инициализатору. Если *initializer* вызовет исключение, все текущие ожидающие задачи вызовут [`BrokenThreadPool`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.thread.BrokenThreadPool), а также любая попытка отправить дополнительные задачи в пул.126127Изменено в версии 3.5: Если *max\_workers* равен `None` или не указан, он будет по умолчанию равен количеству процессоров на машине, умноженному на `5`, исходя из предположения, что `ThreadPoolExecutor` часто используется для перекрытия операций ввода-вывода, а не для загрузки ЦП, и количество рабочих должно быть больше, чем количество рабочих для [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor).128129Изменено в версии 3.6: Добавлен параметр *thread\_name\_prefix*, позволяющий пользователям управлять [`threading.Thread`](https://python-all.ru/3.16/library/threading.html#threading.Thread) именами рабочих потоков, создаваемых пулом, для упрощения отладки.130131Изменено в версии 3.7: Добавлены аргументы *initializer* и *initargs*.132133Изменено в версии 3.8: Значение по умолчанию *max\_workers* изменено на `min(32, os.cpu_count() + 4)`. Это значение по умолчанию сохраняет не менее 5 рабочих для задач, связанных с вводом-выводом. Оно использует не более 32 ядер ЦП для задач, связанных с ЦП и отпускающих GIL. И оно позволяет избежать неявного использования очень больших ресурсов на многоядерных машинах.134135ThreadPoolExecutor теперь также повторно использует простаивающие рабочие потоки, прежде чем запускать *max\_workers* рабочих потоков.136137Изменено в версии 3.13: Значение по умолчанию *max\_workers* изменено на `min(32, (os.process_cpu_count() or 1) + 4)`.138139### Пример ThreadPoolExecutor140141```python142import concurrent.futures143import urllib.request144145URLS = ['http://www.foxnews.com/',146        'http://www.cnn.com/',147        'http://europe.wsj.com/',148        'http://www.bbc.co.uk/',149        'http://nonexistent-subdomain.python.org/']150151# Получить одну страницу и вывести URL и содержимое152def load_url(url, timeout):153    with urllib.request.urlopen(url, timeout=timeout) as conn:154        return conn.read()155156# Можно использовать инструкцию with, чтобы гарантировать своевременную очистку потоков157with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:158    # Запустить операции загрузки и пометить каждый future его URL159    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}160    for future in concurrent.futures.as_completed(future_to_url):161        url = future_to_url[future]162        try:163            data = future.result()164        except Exception as exc:165            print('%r generated an exception: %s' % (url, exc))166        else:167            print('%r page is %d bytes' % (url, len(data)))168```169170## InterpreterPoolExecutor171172Добавлено в версии 3.14.173174Класс [`InterpreterPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.InterpreterPoolExecutor) использует пул интерпретаторов для асинхронного выполнения вызовов. Он является подклассом [`ThreadPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor), что означает, что каждый рабочий выполняется в своём собственном потоке. Отличие здесь в том, что каждый рабочий имеет свой собственный интерпретатор и выполняет каждую задачу с использованием этого интерпретатора.175176Самое большое преимущество использования интерпретаторов вместо только потоков – это настоящий многоядерный параллелизм. Каждый интерпретатор имеет свой собственный [Глобальная блокировка интерпретатора](https://python-all.ru/3.16/glossary.html#term-global-interpreter-lock), поэтому код, выполняемый в одном интерпретаторе, может работать на одном ядре ЦП, в то время как код в другом интерпретаторе выполняется без блокировок на другом ядре.177178Обратная сторона в том, что написание параллельного кода для использования с несколькими интерпретаторами может потребовать дополнительных усилий. Однако это связано с тем, что он заставляет обдуманно подходить к тому, как и когда интерпретаторы взаимодействуют, и явно указывать, какие данные передаются между интерпретаторами. Это даёт несколько преимуществ, которые помогают компенсировать дополнительные усилия, включая настоящий многоядерный параллелизм. Например, код, написанный таким образом, может упростить понимание параллелизма. Ещё одно важное преимущество – вам не нужно иметь дело с рядом серьёзных проблем использования потоков, таких как состояния гонки.179180Интерпретатор каждого рабочего изолирован от всех остальных интерпретаторов. «Изолирован» означает, что каждый интерпретатор имеет собственное состояние выполнения и работает полностью независимо. Например, если перенаправить [`sys.stdout`](https://python-all.ru/3.16/library/sys.html#sys.stdout) в одном интерпретаторе, это не приведёт к автоматическому перенаправлению в любом другом интерпретаторе. Если импортировать модуль в одном интерпретаторе, он не будет автоматически импортирован в другом. Вам придётся импортировать модуль отдельно в том интерпретаторе, где он нужен. Фактически каждый модуль, импортированный в одном интерпретаторе, является полностью отдельным объектом по сравнению с тем же модулем в другом интерпретаторе, включая [`sys`](https://python-all.ru/3.16/library/sys.html#module-sys), [`builtins`](https://python-all.ru/3.16/library/builtins.html#module-builtins), и даже `__main__`.181182Изоляция означает, что изменяемый объект или другие данные не могут использоваться более чем одним интерпретатором одновременно. Это фактически означает, что интерпретаторы не могут совместно использовать такие объекты или данные. Вместо этого каждый интерпретатор должен иметь свою собственную копию, и вам придётся вручную синхронизировать любые изменения между копиями. Неизменяемые объекты и данные, такие как встроенные синглтоны, строки и кортежи неизменяемых объектов, не имеют этих ограничений.183184Передача данных и синхронизация между интерпретаторами наиболее эффективно выполняются с помощью специализированных инструментов, таких как предложенные в [**PEP 734**](https://python-all.ru/3.16/library/concurrent.futures.html). Один менее эффективный альтернативный подход – сериализация с помощью [`pickle`](https://python-all.ru/3.16/library/pickle.html#module-pickle) и затем отправка байтов через общий [`socket`](https://python-all.ru/3.16/library/socket.html#module-socket) или [`pipe`](https://python-all.ru/3.16/library/os.html#os.pipe).185186#### `class concurrent.futures.InterpreterPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())`187188Подкласс [`ThreadPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor), который выполняет вызовы асинхронно, используя пул не более чем из *max\_workers* потоков. Каждый поток выполняет задачи в своём собственном интерпретаторе. Рабочие интерпретаторы изолированы друг от друга, то есть каждый имеет собственное состояние выполнения и они не могут совместно использовать изменяемые объекты или другие данные. Каждый интерпретатор имеет свой собственный [Глобальная блокировка интерпретатора](https://python-all.ru/3.16/glossary.html#term-global-interpreter-lock), что означает, что код, выполняемый с этим исполнителем, обладает настоящим многоядерным параллелизмом.189190Необязательные аргументы *initializer* и *initargs* имеют тот же смысл, что и для `ThreadPoolExecutor`: инициализатор запускается при создании каждого рабочего, хотя в данном случае он запускается в интерпретаторе рабочего. Исполнитель сериализует *initializer* и *initargs* с помощью [`pickle`](https://python-all.ru/3.16/library/pickle.html#module-pickle) при их отправке в интерпретатор рабочего.191192> **Примечание**193>194> Исполнитель может заменять неперехваченные исключения из *initializer* на [`ExecutionFailed`](https://python-all.ru/3.16/library/concurrent.interpreters.html#concurrent.interpreters.ExecutionFailed).195196Другие предостережения от родительского [`ThreadPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) применимы и здесь.197198[`submit()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.submit) и [`map()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.map) работают как обычно, за исключением того, что рабочий сериализует вызываемый объект и аргументы с помощью [`pickle`](https://python-all.ru/3.16/library/pickle.html#module-pickle) при отправке их в свой интерпретатор. Рабочий также сериализует возвращаемое значение при отправке его обратно.199200Когда текущая задача рабочего вызывает неперехваченное исключение, рабочий всегда пытается сохранить исключение как есть. Если это удаётся, то он также устанавливает `__cause__` в соответствующий экземпляр [`ExecutionFailed`](https://python-all.ru/3.16/library/concurrent.interpreters.html#concurrent.interpreters.ExecutionFailed), который содержит сводку исходного исключения. В редком случае, когда рабочий не может сохранить исходное исключение как есть, он вместо этого напрямую сохраняет соответствующий экземпляр `ExecutionFailed`.201202## ProcessPoolExecutor203204Класс [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) является подклассом [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor), который использует пул процессов для асинхронного выполнения вызовов. `ProcessPoolExecutor` использует модуль [`multiprocessing`](https://python-all.ru/3.16/library/multiprocessing.html#module-multiprocessing), что позволяет обойти [Глобальная блокировка интерпретатора](https://python-all.ru/3.16/glossary.html#term-global-interpreter-lock), но также означает, что только picklable-объекты могут быть выполнены и возвращены.205206Модуль `__main__` должен быть импортируемым рабочими подпроцессами. Это означает, что [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) не будет работать в интерактивном интерпретаторе.207208Вызов методов [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor) или [`Future`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future) из вызываемого объекта, отправленного в [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor), приведёт к взаимоблокировке.209210Обратите внимание, что ограничения на функции и аргументы, требующие возможности сериализации через pickle, в соответствии с [`multiprocessing.Process`](https://python-all.ru/3.16/library/multiprocessing.html#multiprocessing.Process) применяются при использовании [`submit()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.submit) и [`map()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.map) на [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor). Не следует ожидать, что функция, определённая в интерактивном интерпретаторе (REPL), или лямбда-функция будут работать.211212#### `class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None)`213214Подкласс [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor), который выполняет вызовы асинхронно, используя пул из не более чем *max\_workers* процессов. Если *max\_workers* равен `None` или не указан, по умолчанию будет использоваться [`os.process_cpu_count()`](https://python-all.ru/3.16/library/os.html#os.process_cpu_count). Если *max\_workers* меньше или равен `0`, то будет вызвано исключение [`ValueError`](https://python-all.ru/3.16/library/exceptions.html#ValueError). В Windows *max\_workers* должен быть меньше или равен `61`. Если это не так, то будет вызвано `ValueError`. Если *max\_workers* равен `None`, то выбранное по умолчанию значение будет не больше `61`, даже если доступно больше процессоров. *mp\_context* может быть контекстом [`multiprocessing`](https://python-all.ru/3.16/library/multiprocessing.html#module-multiprocessing) или `None`. Он будет использоваться для запуска рабочих процессов. Если *mp\_context* равен `None` или не указан, используется контекст по умолчанию `multiprocessing`. См. [Контексты и методы запуска](https://python-all.ru/3.16/library/multiprocessing.html#multiprocessing-start-methods).215216*initializer* – необязательный вызываемый объект, который вызывается при запуске каждого рабочего процесса; *initargs* – кортеж аргументов, передаваемых инициализатору. Если *initializer* вызывает исключение, все текущие ожидающие задания вызовут [`BrokenProcessPool`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.process.BrokenProcessPool), как и любая попытка отправить новые задания в пул.217218*max\_tasks\_per\_child* – необязательный аргумент, задающий максимальное количество задач, которое может выполнить один процесс, прежде чем он завершится и будет заменён новым рабочим процессом. По умолчанию *max\_tasks\_per\_child* равен `None`, что означает, что рабочие процессы будут жить столько же, сколько и пул. Если задан максимум, по умолчанию будет использоваться метод запуска "spawn" multiprocessing при отсутствии параметра *mp\_context*. Эта возможность несовместима с методом запуска "fork".219220Изменено в версии 3.3: Теперь, когда один из рабочих процессов внезапно завершается, возникает ошибка [`BrokenProcessPool`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.process.BrokenProcessPool). Ранее поведение было неопределённым, но операции с исполнителем или его future часто зависали или приводили к взаимоблокировке.221222Изменено в версии 3.7: Добавлен аргумент *mp\_context*, позволяющий пользователям управлять start\_method для рабочих процессов, создаваемых пулом.223224Добавлены аргументы *initializer* и *initargs*.225226Изменено в версии 3.11: Добавлен аргумент *max\_tasks\_per\_child*, позволяющий пользователям контролировать время жизни рабочих процессов в пуле.227228Изменено в версии 3.12: В системах POSIX, если приложение имеет несколько потоков и контекст [`multiprocessing`](https://python-all.ru/3.16/library/multiprocessing.html#module-multiprocessing) использует метод запуска `"fork"`: функция [`os.fork()`](https://python-all.ru/3.16/library/os.html#os.fork), вызываемая внутри для порождения рабочих процессов, может вызвать [`DeprecationWarning`](https://python-all.ru/3.16/library/exceptions.html#DeprecationWarning). Передайте *mp\_context*, настроенный на использование другого метода запуска. См. документацию `os.fork()` для дальнейших пояснений.229230Изменено в версии 3.13: *max\_workers* по умолчанию использует [`os.process_cpu_count()`](https://python-all.ru/3.16/library/os.html#os.process_cpu_count) вместо [`os.cpu_count()`](https://python-all.ru/3.16/library/os.html#os.cpu_count).231232Изменено в версии 3.14: Метод запуска процесса по умолчанию (см. [Контексты и методы запуска](https://python-all.ru/3.16/library/multiprocessing.html#multiprocessing-start-methods)) больше не использует *fork*. Если требуется метод запуска *fork* для `ProcessPoolExecutor`, необходимо явно передать `mp_context=multiprocessing.get_context("fork")`.233234Изменено в версии 3.16.0a0 (не выпущена): Исправлена взаимоблокировка ([gh-115634](https://python-all.ru/3.16/library/concurrent.futures.html)), при которой исполнитель мог зависнуть после\\ nтого как рабочий процесс завершился, достигнув *max\_tasks\_per\_child* лимита, в то время как задачи оставались в очереди.235236#### `terminate_workers()`237238Пытается немедленно завершить все живые рабочие процессы, вызывая [`Process.terminate`](https://python-all.ru/3.16/library/multiprocessing.html#multiprocessing.Process.terminate) для каждого из них. Внутри также вызывает [`Executor.shutdown()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.shutdown), чтобы гарантировать освобождение всех остальных ресурсов, связанных с исполнителем.239240После вызова этого метода вызывающая сторона не должна больше отправлять задачи исполнителю.241242Добавлено в версии 3.14.243244#### `kill_workers()`245246Пытается немедленно уничтожить все живые рабочие процессы, вызывая [`Process.kill`](https://python-all.ru/3.16/library/multiprocessing.html#multiprocessing.Process.kill) для каждого из них. Внутри также вызывает [`Executor.shutdown()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.shutdown), чтобы гарантировать освобождение всех остальных ресурсов, связанных с исполнителем.247248После вызова этого метода вызывающая сторона не должна больше отправлять задачи исполнителю.249250Добавлено в версии 3.14.251252### Пример ProcessPoolExecutor253254```python255import concurrent.futures256import math257258PRIMES = [259    112272535095293,260    112582705942171,261    112272535095293,262    115280095190773,263    115797848077099,264    1099726899285419]265266def is_prime(n):267    if n < 2:268        return False269    if n == 2:270        return True271    if n % 2 == 0:272        return False273274    sqrt_n = int(math.floor(math.sqrt(n)))275    for i in range(3, sqrt_n + 1, 2):276        if n % i == 0:277            return False278    return True279280def main():281    with concurrent.futures.ProcessPoolExecutor() as executor:282        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):283            print('%d is prime: %s' % (number, prime))284285if __name__ == '__main__':286    main()287```288289## Объекты Future290291Класс [`Future`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future) инкапсулирует асинхронное выполнение вызываемого объекта. Экземпляры `Future` создаются с помощью [`Executor.submit()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.submit).292293#### `class concurrent.futures.Future`294295Инкапсулирует асинхронное выполнение вызываемого объекта. Экземпляры `Future` создаются с помощью [`Executor.submit()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor.submit) и не должны создаваться напрямую, за исключением тестирования.296297#### `cancel()`298299Пытается отменить вызов. Если вызов в данный момент выполняется или уже завершён и не может быть отменён, метод вернёт `False`, в противном случае вызов будет отменён и метод вернёт `True`.300301#### `cancelled()`302303Возвращает `True`, если вызов был успешно отменён.304305#### `running()`306307Возвращает `True`, если вызов в данный момент выполняется и не может быть отменён.308309#### `done()`310311Возвращает `True`, если вызов был успешно отменён или завершён.312313#### `result(timeout=None)`314315Возвращает значение, возвращённое вызовом. Если вызов ещё не завершился, этот метод будет ждать до *timeout* секунд. Если вызов не завершится за *timeout* секунд, будет вызвано [`TimeoutError`](https://python-all.ru/3.16/library/exceptions.html#TimeoutError). *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или равен `None`, время ожидания не ограничено.316317Если future отменён до завершения, будет вызвано [`CancelledError`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.CancelledError).318319Если вызов вызвал исключение, этот метод вызовет то же самое исключение.320321#### `exception(timeout=None)`322323Возвращает исключение, вызванное вызовом. Если вызов ещё не завершён, этот метод будет ожидать до *timeout* секунд. Если вызов не завершится за *timeout* секунд, будет вызвано [`TimeoutError`](https://python-all.ru/3.16/library/exceptions.html#TimeoutError). *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или `None`, время ожидания не ограничено.324325Если future отменён до завершения, будет вызвано [`CancelledError`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.CancelledError).326327Если вызов завершился без исключения, возвращается `None`.328329#### `add_done_callback(fn)`330331Прикрепляет вызываемый объект *fn* к future. *fn* будет вызван с future в качестве единственного аргумента, когда future отменён или завершит выполнение.332333Добавленные вызываемые объекты вызываются в порядке их добавления и всегда вызываются в потоке, принадлежащем процессу, который их добавил. Если вызываемый объект вызывает подкласс [`Exception`](https://python-all.ru/3.16/library/exceptions.html#Exception), это будет зарегистрировано и проигнорировано. Если вызываемый объект вызывает подкласс [`BaseException`](https://python-all.ru/3.16/library/exceptions.html#BaseException), поведение не определено.334335Если future уже завершён или отменён, *fn* будет вызван немедленно.336337Следующие методы `Future` предназначены для использования в модульных тестах и реализациях [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor).338339#### `set_running_or_notify_cancel()`340341Этот метод должен вызываться только реализациями [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor) перед выполнением работы, связанной с `Future`, и модульными тестами.342343Если метод возвращает `False`, то `Future` был отменён, то есть [`Future.cancel()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future.cancel) был вызван и вернул `True`. Все потоки, ожидающие завершения `Future` (например, через [`as_completed()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.as_completed) или [`wait()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.wait)), будут разбужены.344345Если метод возвращает `True`, то `Future` не был отменён и переведён в состояние выполнения, то есть вызовы [`Future.running()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future.running) будут возвращать `True`.346347Этот метод можно вызвать только один раз, и его нельзя вызывать после вызова [`Future.set_result()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future.set_result) или [`Future.set_exception()`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future.set_exception).348349#### `set_result(result)`350351Устанавливает результат работы, связанной с `Future`, в *result*.352353Этот метод должен использоваться только реализациями [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor) и модульными тестами.354355Изменено в версии 3.8: Этот метод вызывает [`concurrent.futures.InvalidStateError`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.InvalidStateError), если `Future` уже завершён.356357#### `set_exception(exception)`358359Устанавливает результат работы, связанной с `Future`, в [`Exception`](https://python-all.ru/3.16/library/exceptions.html#Exception) *исключение*.360361Этот метод должен использоваться только реализациями [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor) и модульными тестами.362363Изменено в версии 3.8: Этот метод вызывает [`concurrent.futures.InvalidStateError`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.InvalidStateError), если `Future` уже завершён.364365## Функции модуля366367#### `concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)`368369Ожидает завершения экземпляров [`Future`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future) (возможно, созданных разными экземплярами [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor)), заданных в *fs*. Дублирующиеся future, переданные в *fs*, удаляются и возвращаются только один раз. Возвращает именованный кортеж из двух множеств. Первое множество, названное `done`, содержит future, которые завершились (завершённые или отменённые future) до завершения ожидания. Второе множество, названное `not_done`, содержит future, которые не завершились (ожидающие или выполняющиеся future).370371*timeout* можно использовать для управления максимальным количеством секунд ожидания перед возвратом. *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или `None`, время ожидания не ограничено.372373*return\_when* указывает, когда эта функция должна вернуть результат. Он должен быть одной из следующих констант:374375| Константа | Описание |376| --- | --- |377| concurrent.futures.FIRST\_COMPLETED | Функция возвращает результат, когда любой future завершается или отменяется. |378| concurrent.futures.FIRST\_EXCEPTION | Функция вернёт результат, когда любой future завершится, возбудив исключение. Если ни один future не возбудит исключение, то это эквивалентно [`ALL_COMPLETED`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ALL_COMPLETED). |379| concurrent.futures.ALL\_COMPLETED | Функция вернёт результат, когда все futures завершатся или будут отменены. |380381#### `concurrent.futures.as_completed(fs, timeout=None)`382383Возвращает итератор по экземплярам [`Future`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Future) (возможно, созданным разными экземплярами [`Executor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.Executor)), заданным в *fs*, который выдаёт future по мере их завершения (завершённые или отменённые future). Любые future, переданные в *fs*, которые дублируются, будут возвращены один раз. Все future, завершившиеся до вызова `as_completed()`, будут выданы первыми. Возвращаемый итератор вызывает [`TimeoutError`](https://python-all.ru/3.16/library/exceptions.html#TimeoutError), если [`__next__()`](https://python-all.ru/3.16/library/stdtypes.html#iterator.__next__) вызывается, а результат недоступен через *timeout* секунд после исходного вызова `as_completed()`. *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или `None`, время ожидания не ограничено.384385> **См. также**386>387> **[**PEP 3148**](https://python-all.ru/3.16/library/concurrent.futures.html) – futures - execute computations asynchronously**388>389> Предложение, которое описывало эту возможность для включения в стандартную библиотеку Python.390391## Классы исключений392393#### `exception concurrent.futures.CancelledError`394395Возникает при отмене future.396397#### `exception concurrent.futures.TimeoutError`398399Устаревший псевдоним `TimeoutError`, возникает, когда операция с future превышает заданный таймаут.400401Изменено в версии 3.11: Этот класс стал псевдонимом для `TimeoutError`.402403#### `exception concurrent.futures.BrokenExecutor`404405Производный от [`RuntimeError`](https://python-all.ru/3.16/library/exceptions.html#RuntimeError), этот класс исключения возникает, когда исполнитель по какой-то причине сломан и не может использоваться для отправки или выполнения новых задач.406407Добавлено в версии 3.7.408409#### `exception concurrent.futures.InvalidStateError`410411Возникает, когда над future выполняется операция, которая не разрешена в текущем состоянии.412413Добавлено в версии 3.8.414415#### `exception concurrent.futures.thread.BrokenThreadPool`416417Производный от [`BrokenExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.BrokenExecutor), этот класс исключения возникает, когда один из рабочих потоков [`ThreadPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) не смог инициализироваться.418419Добавлено в версии 3.7.420421#### `exception concurrent.futures.interpreter.BrokenInterpreterPool`422423Производный от [`BrokenThreadPool`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.thread.BrokenThreadPool), этот класс исключения возникает, когда один из рабочих процессов [`InterpreterPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.InterpreterPoolExecutor) не смог инициализироваться.424425Добавлено в версии 3.14.426427#### `exception concurrent.futures.process.BrokenProcessPool`428429Производный от [`BrokenExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.BrokenExecutor) (ранее [`RuntimeError`](https://python-all.ru/3.16/library/exceptions.html#RuntimeError)), этот класс исключения возникает, когда один из рабочих процессов [`ProcessPoolExecutor`](https://python-all.ru/3.16/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) завершился нечисто (например, если он был убит извне).430431Добавлено в версии 3.3.432