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

concurrent.futures.md

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

1> **Источник:** https://python-all.ru/3.5/library/concurrent.futures.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 17.4. [`concurrent.futures`](https://python-all.ru/3.5/library/concurrent.futures.html#module-concurrent.futures) – Запуск параллельных задач89Новое в версии 3.2.1011**Исходный код:** [Lib/concurrent/futures/thread.py](https://python-all.ru/src/3.5/Lib/concurrent/futures/thread.py) и [Lib/concurrent/futures/process.py](https://python-all.ru/src/3.5/Lib/concurrent/futures/process.py)1213---1415Модуль [`concurrent.futures`](https://python-all.ru/3.5/library/concurrent.futures.html#module-concurrent.futures) предоставляет высокоуровневый интерфейс для асинхронного выполнения вызываемых объектов.1617Асинхронное выполнение может выполняться с помощью потоков, используя [`ThreadPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor), или отдельных процессов, используя [`ProcessPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor). Оба реализуют один и тот же интерфейс, определяемый абстрактным классом [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor).1819## 17.4.1. Объекты исполнителя2021#### `class concurrent.futures.Executor`2223Абстрактный класс, предоставляющий методы для асинхронного выполнения вызовов. Его не следует использовать напрямую, а через его конкретные подклассы.2425> #### `submit(fn, *args, **kwargs)`26>27> Планирует выполнение вызываемого объекта *fn* как `fn(*args **kwargs)` и возвращает объект [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future), представляющий выполнение вызываемого объекта.28>29> ```python30> with ThreadPoolExecutor(max_workers=1) as executor:31>     future = executor.submit(pow, 323, 1235)32>     print(future.result())33> ```34>35> #### `map(func, *iterables, timeout=None, chunksize=1)`36>37> Эквивалентно [`map(func, *iterables)`](https://python-all.ru/3.5/library/functions.html#map), за исключением того, что *func* выполняется\\nасинхронно и несколько вызовов *func* могут выполняться параллельно. Возвращаемый\\nитератор возбуждает [`concurrent.futures.TimeoutError`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.TimeoutError), если\\nвызван [`__next__()`](https://python-all.ru/3.5/library/stdtypes.html#iterator.__next__) и результат недоступен\\nпо истечении *timeout* секунд с момента исходного вызова [`Executor.map()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor.map).\\n*timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или\\n`None`, время ожидания не ограничено. Если при вызове возникает\\nисключение, оно будет возбуждено при извлечении его значения\\nиз итератора. При использовании [`ProcessPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) этот\\nметод разбивает *iterables* на несколько блоков, которые передаются в\\nпул как отдельные задачи. Приблизительный размер этих блоков можно\\nзадать, указав *chunksize* в виде положительного целого числа. Для очень длинных\\nитераций использование большого значения *chunksize* может значительно повысить\\nпроизводительность по сравнению со значением по умолчанию 1. При использовании [`ThreadPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor),\\n*chunksize* не влияет на работу.38>39> Изменено в версии 3.5: Добавлен аргумент *chunksize*.40>41> #### `shutdown(wait=True)`42>43> Сообщает исполнителю, что он должен освободить все используемые ресурсы, когда текущие ожидающие future завершат выполнение. Вызовы [`Executor.submit()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor.submit) и [`Executor.map()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor.map) после shutdown приведут к возбуждению [`RuntimeError`](https://python-all.ru/3.5/library/exceptions.html#RuntimeError).44>45> Если *wait* равен `True`, то этот метод не вернёт управление, пока все ожидающие future не завершат выполнение и ресурсы, связанные с исполнителем, не будут освобождены. Если *wait* равен `False`, то метод вернёт управление немедленно, а ресурсы, связанные с исполнителем, будут освобождены, когда все ожидающие future завершат выполнение. Независимо от значения *wait*, вся программа Python не завершится, пока все ожидающие future не завершат выполнение.46>47> Вы можете избежать явного вызова этого метода, если используете оператор [`with`](https://python-all.ru/3.5/reference/compound_stmts.html#with), который завершит работу [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor) (ожидая, как если бы [`Executor.shutdown()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor.shutdown) был вызван с *wait*, установленным в `True`):48>49> ```python50> import shutil51> with ThreadPoolExecutor(max_workers=4) as e:52>     e.submit(shutil.copy, 'src1.txt', 'dest1.txt')53>     e.submit(shutil.copy, 'src2.txt', 'dest2.txt')54>     e.submit(shutil.copy, 'src3.txt', 'dest3.txt')55>     e.submit(shutil.copy, 'src4.txt', 'dest4.txt')56> ```5758## 17.4.2. ThreadPoolExecutor5960[`ThreadPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) – подкласс [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor), использующий пул потоков для асинхронного выполнения вызовов.6162Взаимоблокировки могут возникать, когда вызываемый объект, связанный с [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future), ожидает результаты другого [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future). Например:6364```python65import time66def wait_on_b():67    time.sleep(5)68    print(b.result())  # b никогда не завершится, потому что он ожидает a.69    return 57071def wait_on_a():72    time.sleep(5)73    print(a.result())  # a никогда не завершится, потому что он ожидает b.74    return 67576executor = ThreadPoolExecutor(max_workers=2)77a = executor.submit(wait_on_b)78b = executor.submit(wait_on_a)79```8081И:8283```python84def wait_on_future():85    f = executor.submit(pow, 5, 2)86    # Это никогда не завершится, потому что есть только один рабочий поток и87    # он выполняет эту функцию.88    print(f.result())8990executor = ThreadPoolExecutor(max_workers=1)91executor.submit(wait_on_future)92```9394#### `class concurrent.futures.ThreadPoolExecutor(max_workers=None)`9596Подкласс [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor), который использует пул не более чем из *max\_workers* потоков для асинхронного выполнения вызовов.9798Изменено в версии 3.5: Если *max\_workers* равен `None` или не указан, он будет по умолчанию равен количеству процессоров на машине, умноженному на `5`, исходя из предположения, что [`ThreadPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) часто используется для перекрытия операций ввода-вывода, а не для загрузки ЦП, и количество рабочих должно быть больше, чем количество рабочих для [`ProcessPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor).99100### 17.4.2.1. Пример ThreadPoolExecutor101102```python103import concurrent.futures104import urllib.request105106URLS = ['http://www.foxnews.com/',107        'http://www.cnn.com/',108        'http://europe.wsj.com/',109        'http://www.bbc.co.uk/',110        'http://some-made-up-domain.com/']111112# Получить одну страницу и вывести URL и содержимое113def load_url(url, timeout):114    with urllib.request.urlopen(url, timeout=timeout) as conn:115        return conn.read()116117# Можно использовать инструкцию with, чтобы гарантировать своевременную очистку потоков118with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:119    # Запустить операции загрузки и пометить каждый future его URL120    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}121    for future in concurrent.futures.as_completed(future_to_url):122        url = future_to_url[future]123        try:124            data = future.result()125        except Exception as exc:126            print('%r generated an exception: %s' % (url, exc))127        else:128            print('%r page is %d bytes' % (url, len(data)))129```130131## 17.4.3. ProcessPoolExecutor132133Класс [`ProcessPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) является подклассом [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor), который использует пул процессов для асинхронного выполнения вызовов. [`ProcessPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) использует модуль [`multiprocessing`](https://python-all.ru/3.5/library/multiprocessing.html#module-multiprocessing), что позволяет обойти [Глобальная блокировка интерпретатора](https://python-all.ru/3.5/glossary.html#term-global-interpreter-lock), но также означает, что только picklable-объекты могут быть выполнены и возвращены.134135Модуль `__main__` должен быть импортируемым рабочими подпроцессами. Это означает, что [`ProcessPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) не будет работать в интерактивном интерпретаторе.136137Вызов методов [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor) или [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) из вызываемого объекта, отправленного в [`ProcessPoolExecutor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor), приведёт к взаимоблокировке.138139#### `class concurrent.futures.ProcessPoolExecutor(max_workers=None)`140141Подкласс [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor), который выполняет вызовы асинхронно, используя пул из не более *max\_workers* процессов. Если *max\_workers* равен `None` или не указан, по умолчанию используется количество процессоров в машине. Если *max\_workers* меньше или равен `0`, то возбуждается [`ValueError`](https://python-all.ru/3.5/library/exceptions.html#ValueError).142143Изменено в версии 3.3: Когда один из рабочих процессов завершается аварийно, теперь возбуждается ошибка `BrokenProcessPool`. Ранее поведение было неопределённым, но операции над исполнителем или его future часто приводили к зависанию или взаимоблокировке.144145### 17.4.3.1. Пример ProcessPoolExecutor146147```python148import concurrent.futures149import math150151PRIMES = [152    112272535095293,153    112582705942171,154    112272535095293,155    115280095190773,156    115797848077099,157    1099726899285419]158159def is_prime(n):160    if n % 2 == 0:161        return False162163    sqrt_n = int(math.floor(math.sqrt(n)))164    for i in range(3, sqrt_n + 1, 2):165        if n % i == 0:166            return False167    return True168169def main():170    with concurrent.futures.ProcessPoolExecutor() as executor:171        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):172            print('%d is prime: %s' % (number, prime))173174if __name__ == '__main__':175    main()176```177178## 17.4.4. Объекты Future179180Класс [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) инкапсулирует асинхронное выполнение вызываемого объекта. Экземпляры [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) создаются с помощью [`Executor.submit()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor.submit).181182#### `class concurrent.futures.Future`183184Инкапсулирует асинхронное выполнение вызываемого объекта. Экземпляры [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) создаются с помощью [`Executor.submit()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor.submit) и не должны создаваться напрямую, за исключением тестирования.185186> #### `cancel()`187>188> Пытается отменить вызов. Если вызов в данный момент выполняется и не может быть отменён, метод вернёт `False`, в противном случае вызов будет отменён и метод вернёт `True`.189>190> #### `cancelled()`191>192> Возвращает `True`, если вызов был успешно отменён.193>194> #### `running()`195>196> Возвращает `True`, если вызов в данный момент выполняется и не может быть отменён.197>198> #### `done()`199>200> Возвращает `True`, если вызов был успешно отменён или завершён.201>202> #### `result(timeout=None)`203>204> Возвращает значение, возвращённое вызовом. Если вызов ещё не завершился, этот метод будет ждать до *timeout* секунд. Если вызов не завершится за *timeout* секунд, будет вызвано [`concurrent.futures.TimeoutError`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.TimeoutError). *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или равен `None`, время ожидания не ограничено.205>206> Если future отменён до завершения, будет вызвано [`CancelledError`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.CancelledError).207>208> Если вызов вызвал исключение, этот метод возбудит то же самое исключение.209>210> #### `exception(timeout=None)`211>212> Возвращает исключение, вызванное вызовом. Если вызов ещё не завершён, этот метод будет ожидать до *timeout* секунд. Если вызов не завершится за *timeout* секунд, будет вызвано [`concurrent.futures.TimeoutError`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.TimeoutError). *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или `None`, время ожидания не ограничено.213>214> Если future отменён до завершения, будет вызвано [`CancelledError`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.CancelledError).215>216> Если вызов завершился без исключения, возвращается `None`.217>218> #### `add_done_callback(fn)`219>220> Прикрепляет вызываемый объект *fn* к future. *fn* будет вызван с future в качестве единственного аргумента, когда future отменён или завершит выполнение.221>222> Добавленные вызываемые объекты вызываются в порядке их добавления и всегда вызываются в потоке, принадлежащем процессу, который их добавил. Если вызываемый объект вызывает подкласс [`Exception`](https://python-all.ru/3.5/library/exceptions.html#Exception), это будет зарегистрировано и проигнорировано. Если вызываемый объект вызывает подкласс [`BaseException`](https://python-all.ru/3.5/library/exceptions.html#BaseException), поведение не определено.223>224> Если future уже завершён или отменён, *fn* будет вызван немедленно.225226Следующие методы [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) предназначены для использования в модульных тестах и реализациях [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor).227228> #### `set_running_or_notify_cancel()`229>230> Этот метод должен вызываться только реализациями [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor) перед выполнением работы, связанной с [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future), и модульными тестами.231>232> Если метод возвращает `False`, значит, [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) был отменён, то есть был вызван [`Future.cancel()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future.cancel), и он вернул *True*. Все потоки, ожидающие завершения [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) (например, через [`as_completed()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.as_completed) или [`wait()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.wait)), будут разбужены.233>234> Если метод возвращает `True`, значит, [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) не был отменён и переведён в состояние выполнения, то есть вызовы [`Future.running()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future.running) будут возвращать *True*.235>236> Этот метод можно вызвать только один раз, и его нельзя вызывать после вызова [`Future.set_result()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future.set_result) или [`Future.set_exception()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future.set_exception).237>238> #### `set_result(result)`239>240> Устанавливает результат работы, связанной с [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future), в *result*.241>242> Этот метод должен использоваться только реализациями [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor) и модульными тестами.243>244> #### `set_exception(exception)`245>246> Устанавливает результат работы, связанной с [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future), в [`Exception`](https://python-all.ru/3.5/library/exceptions.html#Exception) *исключение*.247>248> Этот метод должен использоваться только реализациями [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor) и модульными тестами.249250## 17.4.5. Функции модуля251252#### `concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)`253254Ожидает завершения экземпляров [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) (возможно, созданных разными экземплярами [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor)), заданных в *fs*. Возвращает именованный кортеж из двух множеств. Первое множество, называемое `done`, содержит futures, которые завершились (выполнились или были отменены) до завершения ожидания. Второе множество, называемое `not_done`, содержит незавершённые futures.255256*timeout* можно использовать для управления максимальным количеством секунд ожидания перед возвратом. *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или `None`, время ожидания не ограничено.257258*return\_when* указывает, когда эта функция должна вернуть результат. Он должен быть одной из следующих констант:259260| Константа | Описание |261| --- | --- |262| `FIRST_COMPLETED` | Функция вернёт результат, когда любой future завершится или будет отменён. |263| `FIRST_EXCEPTION` | Функция вернёт результат, когда любой future завершится, возбудив исключение. Если ни один future не возбудит исключение, это эквивалентно `ALL_COMPLETED`. |264| `ALL_COMPLETED` | Функция вернёт результат, когда все future завершатся или будут отменены. |265266#### `concurrent.futures.as_completed(fs, timeout=None)`267268Возвращает итератор по экземплярам [`Future`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Future) (возможно, созданным разными экземплярами [`Executor`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.Executor)), заданным в *fs*, который генерирует futures по мере их завершения (выполнения или отмены). Любые futures, заданные в *fs*, которые дублируются, будут возвращены один раз. Futures, завершившиеся до вызова [`as_completed()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.as_completed), будут выданы первыми. Возвращённый итератор возбуждает [`concurrent.futures.TimeoutError`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.TimeoutError), если вызывается [`__next__()`](https://python-all.ru/3.5/library/stdtypes.html#iterator.__next__) и результат недоступен через *timeout* секунд после исходного вызова [`as_completed()`](https://python-all.ru/3.5/library/concurrent.futures.html#concurrent.futures.as_completed). *timeout* может быть целым числом или числом с плавающей запятой. Если *timeout* не указан или равен `None`, время ожидания не ограничено.269270> **См. также**271>272> **[**PEP 3148**](https://python-all.ru/3.5/library/concurrent.futures.html) – futures - execute computations asynchronously**273>274> Предложение, которое описывало эту возможность для включения в стандартную библиотеку Python.275276## 17.4.6. Классы исключений277278#### `exception concurrent.futures.CancelledError`279280Возникает при отмене future.281282#### `exception concurrent.futures.TimeoutError`283284Возбуждается, когда операция с future превышает заданный тайм-аут.285286#### `exception concurrent.futures.process.BrokenProcessPool`287288Производный от [`RuntimeError`](https://python-all.ru/3.5/library/exceptions.html#RuntimeError), этот класс исключения возбуждается, когда один из рабочих процессов `ProcessPoolExecutor` завершился некорректно (например, если он был убит извне).289290Новое в версии 3.3.291