concurrent.futures — Запуск параллельных задач
Добавлено в версии 3.2.
Исходный код: Lib/concurrent/futures/thread.py и Lib/concurrent/futures/process.py
Модуль concurrent.futures предоставляет высокоуровневый интерфейс для асинхронного выполнения вызываемых объектов.
Асинхронное выполнение может осуществляться с помощью потоков, используя ThreadPoolExecutor, или отдельных процессов, используя ProcessPoolExecutor. Оба класса реализуют один и тот же интерфейс, определённый абстрактным классом Executor.
Доступность: недоступен в 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), за исключением того, что:- iterables собираются сразу, а не лениво;
- fn выполняется асинхронно, и несколько вызовов fn могут выполняться одновременно.
Возвращаемый итератор возбуждает исключение
TimeoutError, если при вызове__next__()результат недоступен по истечении timeout секунд с момента первоначального вызоваExecutor.map(). Значение timeout может быть целым числом или числом с плавающей точкой. Если timeout не задан или равенNone, время ожидания не ограничено.Если вызов fn возбуждает исключение, оно будет возбуждено при получении соответствующего значения из итератора.
При использовании
ProcessPoolExecutorэтот метод разбивает iterables на несколько фрагментов и отправляет их в пул как отдельные задачи. (Приблизительный) размер этих фрагментов можно задать, установив для chunksize положительное целое число. Для очень длинных итерируемых объектов большое значение chunksize может значительно повысить производительность по сравнению со значением по умолчанию, равным 1. ВThreadPoolExecutorпараметр chunksize не влияет на работу.Изменено в версии 3.5: Добавлен аргумент chunksize.
-
shutdown(wait=True, *, cancel_futures=False) -
Сообщает исполнителю, что он должен освободить все используемые ресурсы после завершения выполнения ожидающих объектов future. Вызовы
Executor.submit()иExecutor.map(), сделанные после завершения работы, возбудят исключениеRuntimeError.Если wait равно
True, этот метод не вернёт управление, пока выполнение всех ожидающих объектов future не завершится и ресурсы, связанные с исполнителем, не будут освобождены. Если wait равноFalse, этот метод немедленно вернёт управление, а ресурсы, связанные с исполнителем, будут освобождены после завершения выполнения всех ожидающих объектов future. Независимо от значения wait, программа Python не завершится, пока выполнение всех ожидающих объектов future не будет завершено.Если cancel_futures равно
True, этот метод отменит все ожидающие объекты future, выполнение которых исполнитель ещё не начал. Объекты future, выполнение которых завершено или уже выполняется, отменены не будут независимо от значения cancel_futures.Если cancel_futures и wait оба равны
True, все объекты future, выполнение которых уже началось, будут завершены до возврата этого метода. Остальные объекты future будут отменены.Необязательно явно вызывать этот метод, если использовать исполнитель в качестве менеджера контекста с помощью инструкции
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 will never complete because it is waiting on a.
return 5
def wait_on_a():
time.sleep(5)
print(a.result()) # a will never complete because it is waiting on 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)
executor.submit(wait_on_future)
-
class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=()) -
Подкласс
Executor, который использует пул не более чем из max_workers потоков для асинхронного выполнения вызовов.Все потоки, поставленные в очередь в
ThreadPoolExecutor, будут объединены до завершения работы интерпретатора. Обратите внимание: обработчик завершения, выполняющий это, запускается до обработчиков завершения, добавленных с помощьюatexit. Это означает, что исключения в главном потоке необходимо перехватывать и обрабатывать, чтобы подать потокам сигнал о необходимости корректного завершения. По этой причине не рекомендуется использоватьThreadPoolExecutorдля длительно выполняющихся задач.initializer — необязательный вызываемый объект, который вызывается в начале работы каждого рабочего потока; initargs — кортеж аргументов, передаваемых функции инициализации. Если initializer возбуждает исключение, все ожидающие в данный момент задания возбудят исключение
BrokenThreadPool, как и любая попытка отправить в пул дополнительные задания.Изменено в версии 3.5: Если max_workers равен
Noneили не задан, по умолчанию используется количество процессоров на компьютере, умноженное на5. Предполагается, чтоThreadPoolExecutorчасто используется для перекрытия операций ввода-вывода, а не вычислений на ЦП, поэтому число рабочих потоков должно быть больше, чем число рабочих процессов вProcessPoolExecutor.Изменено в версии 3.6: Добавлен параметр thread_name_prefix, позволяющий пользователям задавать имена объектов
threading.Threadдля рабочих потоков, создаваемых пулом, что упрощает отладку.Изменено в версии 3.7: Добавлены аргументы initializer и initargs.
Изменено в версии 3.8: Значение max_workers по умолчанию изменено на
min(32, os.cpu_count() + 4). Это значение по умолчанию сохраняет не менее 5 рабочих потоков для задач, ограниченных операциями ввода-вывода. Для задач, ограниченных вычислениями на ЦП и освобождающих GIL, оно задействует не более 32 ядер ЦП. Кроме того, оно позволяет избежать неявного использования чрезмерно большого объёма ресурсов на компьютерах с большим количеством ядер.Теперь 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/']
# 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, что позволяет обойти глобальную блокировку интерпретатора, но также означает, что выполнять и возвращать можно только объекты, поддерживающие сериализацию с помощью pickle.
Модуль __main__ должен быть доступен для импорта рабочими дочерними процессами. Это означает, что ProcessPoolExecutor не будет работать в интерактивном интерпретаторе.
Вызов методов Executor или Future из вызываемого объекта, отправленного в ProcessPoolExecutor, приведёт к взаимной блокировке.
Обратите внимание, что ограничения на сериализуемость функций и аргументов, установленные в multiprocessing.Process, действуют при использовании submit() и map() с ProcessPoolExecutor. Не следует рассчитывать на работу функции, определённой в REPL, или лямбда-функции.
-
class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=(), max_tasks_per_child=None) -
Подкласс
Executor, который асинхронно выполняет вызовы с помощью пула, содержащего не более max_workers процессов. Если 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: Если один из рабочих процессов внезапно завершает работу, теперь возбуждается исключение
BrokenProcessPool. Ранее поведение не было определено, однако операции с исполнителем или его объектами future часто зависали или приводили к взаимной блокировке.Изменено в версии 3.7: Добавлен аргумент mp_context, позволяющий пользователям управлять методом запуска процессов, создаваемых пулом.
Добавлены аргументы initializer и initargs.
Примечание
В Python 3.14 метод запуска по умолчанию
multiprocessing(см. раздел Контексты и методы запуска) изменится с fork на другой. В коде, которому дляProcessPoolExecutorтребуется использовать fork, это следует указать явно, передав параметрmp_context=multiprocessing.get_context("fork").Изменено в версии 3.11: Добавлен аргумент max_tasks_per_child, позволяющий пользователям управлять временем жизни рабочих процессов в пуле.
Изменено в версии 3.12: В системах POSIX, если приложение использует несколько потоков и контекст
multiprocessingиспользует метод запуска"fork", функцияos.fork(), вызываемая внутри для создания рабочих процессов, может возбудить исключениеDeprecationWarning. Передайте mp_context, настроенный на использование другого метода запуска. Дополнительные сведения см. в документации поos.fork().Изменено в версии 3.13: По умолчанию для max_workers используется
os.process_cpu_count()вместоos.cpu_count().
Пример 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 может быть целым числом или числом с плавающей точкой. Если timeout не задан или равенNone, время ожидания не ограничено.Если объект future отменён до завершения, будет возбуждено исключение
CancelledError.Если вызов возбудил исключение, этот метод возбудит то же исключение.
-
exception(timeout=None) -
Возвращает исключение, возбужденное вызовом. Если вызов ещё не завершён, этот метод будет ждать до timeout секунд. Если вызов не завершится за timeout секунд, будет возбуждено исключение
TimeoutError. Значение timeout может быть целым числом или числом с плавающей точкой. Если timeout не задан или равенNone, время ожидания не ограничено.Если объект future отменён до завершения, будет возбуждено исключение
CancelledError.Если вызов завершился без возбуждения исключения, возвращается
None.
-
add_done_callback(fn) -
Добавляет вызываемый объект fn к объекту future. fn будет вызван с объектом future в качестве единственного аргумента после отмены объекта future или завершения его выполнения.
Добавленные вызываемые объекты вызываются в порядке добавления и всегда в потоке процесса, который их добавил. Если вызываемый объект возбуждает исключение, являющееся подклассом
Exception, оно будет записано в журнал и проигнорировано. Если вызываемый объект возбуждает исключение, являющееся подклассомBaseException, поведение не определено.Если объект future уже завершён или отменён, fn будет вызван немедленно.
Следующие методы
Futureпредназначены для использования в модульных тестах и реализацияхExecutor.-
set_running_or_notify_cancel() -
Этот метод следует вызывать только реализациям
Executorперед выполнением работы, связанной сFuture, а также модульным тестам.Если метод возвращает
False, значит,Futureбыл отменён, то есть был вызванFuture.cancel(), вернувшийTrue. Все потоки, ожидающие завершенияFuture(например, с помощьюas_completed()илиwait()), будут разблокированы.Если метод возвращает
True, значит,Futureне был отменён и перешёл в состояние выполнения, то есть вызовыFuture.running()будут возвращатьTrue.Этот метод можно вызвать только один раз, и его нельзя вызывать после вызова
Future.set_result()илиFuture.set_exception().
-
set_result(result) -
Задаёт значение result в качестве результата работы, связанной с
Future.Этот метод следует использовать только в реализациях
Executorи модульных тестах.Изменено в версии 3.8: Этот метод возбуждает исключение
concurrent.futures.InvalidStateError, еслиFutureуже завершён.
-
set_exception(exception) -
Задаёт исключение
Exceptionexception в качестве результата работы, связанной сFuture.Этот метод следует использовать только в реализациях
Executorи модульных тестах.Изменено в версии 3.8: Этот метод возбуждает исключение
concurrent.futures.InvalidStateError, еслиFutureуже завершён.
-
Функции модуля
-
concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED) -
Ожидать завершения экземпляров
Future(возможно, созданных разными экземплярамиExecutor), переданных в fs. Повторяющиеся объекты Future, переданные в fs, удаляются и возвращаются только один раз. Возвращается именованный кортеж из двух множеств. Первое множество с именемdoneсодержит объекты Future, завершившиеся (выполненные или отменённые) до завершения ожидания. Второе множество с именемnot_doneсодержит объекты Future, которые не завершились (ожидающие или выполняющиеся).Параметр timeout позволяет задать максимальное количество секунд ожидания перед возвратом. Значением timeout может быть целое число или число с плавающей точкой. Если timeout не задан или равен
None, время ожидания не ограничено.Параметр return_when указывает, когда должна возвращаться эта функция. Он должен иметь одно из следующих значений:
Константа
Описание
-
concurrent.futures.FIRST_COMPLETED
Функция возвращает результат, когда любой объект Future завершается или отменяется.
-
concurrent.futures.FIRST_EXCEPTION
Функция возвращает результат, когда любой объект Future завершается с возбуждением исключения. Если ни один объект Future не возбуждает исключение, это значение эквивалентно
ALL_COMPLETED.-
concurrent.futures.ALL_COMPLETED
Функция возвращает результат, когда все объекты Future завершатся или будут отменены.
-
-
concurrent.futures.as_completed(fs, timeout=None) -
Возвращает итератор по экземплярам
Future(возможно, созданным разными экземплярамиExecutor), переданным в fs. Итератор выдаёт объекты Future по мере их завершения (выполненные или отменённые объекты Future). Повторяющиеся объекты Future, переданные в fs, возвращаются только один раз. Объекты Future, завершившиеся до вызоваas_completed(), выдаются первыми. Возвращаемый итератор возбуждает исключениеTimeoutError, если вызывается__next__(), а результат недоступен по истечении timeout секунд с момента исходного вызоваas_completed(). Значением timeout может быть целое число или число с плавающей точкой. Если timeout не задан или равенNone, время ожидания не ограничено.
См. также
- PEP 3148 – futures — асинхронное выполнение вычислений
-
Предложение, в котором описывалось включение этой возможности в стандартную библиотеку Python.
Классы исключений
-
exception concurrent.futures.CancelledError -
Возникает, когда объект Future отменён.
-
exception concurrent.futures.TimeoutError -
Устаревший псевдоним
TimeoutError; возникает, когда операция с объектом Future превышает заданное время ожидания.Изменено в версии 3.11: Этот класс стал псевдонимом
TimeoutError.
-
exception concurrent.futures.BrokenExecutor -
Производный от
RuntimeError, этот класс исключений возникает, когда исполнитель по какой-либо причине выходит из строя и не может использоваться для отправки или выполнения новых задач.Добавлено в версии 3.7.
-
exception concurrent.futures.InvalidStateError -
Возникает, когда с объектом Future выполняется операция, недопустимая в его текущем состоянии.
Добавлено в версии 3.8.
-
exception concurrent.futures.thread.BrokenThreadPool -
Производный от
BrokenExecutor, этот класс исключений возникает, когда не удалось инициализировать один из рабочих потоковThreadPoolExecutor.Добавлено в версии 3.7.
-
exception concurrent.futures.process.BrokenProcessPool -
Производный от
BrokenExecutor(ранее — отRuntimeError), этот класс исключений возникает, когда один из рабочих процессовProcessPoolExecutorзавершился некорректно (например, был принудительно остановлен извне).Добавлено в версии 3.3.
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/concurrent.futures.html