Содержание страницы
17.4. concurrent.futures – Запуск параллельных задач¶concurrent.futures – Launching parallel tasks
Новое в версии 3.2.
Исходный код: Lib/concurrent/futures/thread.py и Lib/concurrent/futures/process.py
Модуль concurrent.futures предоставляет высокоуровневый интерфейс для
асинхронного выполнения вызываемых объектов.
Асинхронное выполнение может выполняться с помощью потоков, используя ThreadPoolExecutor, или отдельных процессов, используя ProcessPoolExecutor. Оба реализуют один и тот же интерфейс, определяемый абстрактным классом Executor.
17.4.1. Объекты исполнителя¶Executor Objects
-
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(func, *iterables, timeout=None, chunksize=1)¶ Эквивалентно
map(func, *iterables), за исключением того, что func выполняется\nасинхронно и несколько вызовов func могут выполняться параллельно. Возвращаемый\nитератор возбуждаетconcurrent.futures.TimeoutError, если\nвызван__next__()и результат недоступен\nпо истечении timeout секунд с момента исходного вызоваExecutor.map().\ntimeout может быть целым числом или числом с плавающей запятой. Если timeout не указан или\nNone, время ожидания не ограничено. Если при вызове возникает\nисключение, оно будет возбуждено при извлечении его значения\nиз итератора. При использованииProcessPoolExecutorэтот\nметод разбивает iterables на несколько блоков, которые передаются в\nпул как отдельные задачи. Приблизительный размер этих блоков можно\nзадать, указав chunksize в виде положительного целого числа. Для очень длинных\nитераций использование большого значения chunksize может значительно повысить\nпроизводительность по сравнению со значением по умолчанию 1. При использованииThreadPoolExecutor,\nchunksize не влияет на работу.Изменено в версии 3.5: Добавлен аргумент chunksize.
-
shutdown(wait=True)¶ Сообщает исполнителю, что он должен освободить все используемые ресурсы, когда текущие ожидающие future завершат выполнение. Вызовы
Executor.submit()иExecutor.map()после shutdown приведут к возбуждениюRuntimeError.Если wait равен
True, то этот метод не вернёт управление, пока все ожидающие future не завершат выполнение и ресурсы, связанные с исполнителем, не будут освобождены. Если wait равенFalse, то метод вернёт управление немедленно, а ресурсы, связанные с исполнителем, будут освобождены, когда все ожидающие future завершат выполнение. Независимо от значения wait, вся программа Python не завершится, пока все ожидающие 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')
-
17.4.2. 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)
# Это никогда не завершится, потому что есть только один рабочий поток и
# он выполняет эту функцию.
print(f.result())
executor = ThreadPoolExecutor(max_workers=1)
executor.submit(wait_on_future)
-
class
concurrent.futures.ThreadPoolExecutor(max_workers=None)¶ Подкласс
Executor, который использует пул не более чем из max_workers потоков для асинхронного выполнения вызовов.Изменено в версии 3.5: Если max_workers равен
Noneили не указан, он будет по умолчанию равен количеству процессоров на машине, умноженному на5, исходя из предположения, чтоThreadPoolExecutorчасто используется для перекрытия операций ввода-вывода, а не для загрузки ЦП, и количество рабочих должно быть больше, чем количество рабочих дляProcessPoolExecutor.
17.4.2.1. Пример ThreadPoolExecutor¶ThreadPoolExecutor Example
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://some-made-up-domain.com/']
# Получить одну страницу и вывести URL и содержимое
def load_url(url, timeout):
with urllib.request.urlopen(url, timeout=timeout) as conn:
return conn.read()
# Можно использовать инструкцию with, чтобы гарантировать своевременную очистку потоков
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Запустить операции загрузки и пометить каждый future его 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)))
17.4.3. ProcessPoolExecutor¶
Класс ProcessPoolExecutor является подклассом Executor, который использует пул процессов для асинхронного выполнения вызовов. ProcessPoolExecutor использует модуль multiprocessing, что позволяет обойти Глобальная блокировка интерпретатора, но также означает, что только picklable-объекты могут быть выполнены и возвращены.
Модуль __main__ должен быть импортируемым рабочими подпроцессами. Это означает,
что ProcessPoolExecutor не будет работать в интерактивном интерпретаторе.
Вызов методов Executor или Future из вызываемого объекта, отправленного
в ProcessPoolExecutor, приведёт к взаимоблокировке.
-
class
concurrent.futures.ProcessPoolExecutor(max_workers=None)¶ Подкласс
Executor, который выполняет вызовы асинхронно, используя пул из не более max_workers процессов. Если max_workers равенNoneили не указан, по умолчанию используется количество процессоров в машине. Если max_workers меньше или равен0, то возбуждаетсяValueError.Изменено в версии 3.3: Когда один из рабочих процессов завершается аварийно, теперь возбуждается ошибка
BrokenProcessPool. Ранее поведение было неопределённым, но операции над исполнителем или его future часто приводили к зависанию или взаимоблокировке.
17.4.3.1. Пример ProcessPoolExecutor¶ProcessPoolExecutor Example
import concurrent.futures
import math
PRIMES = [
112272535095293,
112582705942171,
112272535095293,
115280095190773,
115797848077099,
1099726899285419]
def is_prime(n):
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()
17.4.4. Объекты Future¶Future Objects
Класс 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 секунд, будет вызвано
concurrent.futures.TimeoutError. timeout может быть целым числом или числом с плавающей запятой. Если timeout не указан или равенNone, время ожидания не ограничено.Если future отменён до завершения, будет вызвано
CancelledError.Если вызов вызвал исключение, этот метод возбудит то же самое исключение.
-
exception(timeout=None)¶ Возвращает исключение, вызванное вызовом. Если вызов ещё не завершён, этот метод будет ожидать до timeout секунд. Если вызов не завершится за timeout секунд, будет вызвано
concurrent.futures.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().
-
17.4.5. Функции модуля¶Module Functions
-
concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)¶ Ожидает завершения экземпляров
Future(возможно, созданных разными экземплярамиExecutor), заданных в fs. Возвращает именованный кортеж из двух множеств. Первое множество, называемоеdone, содержит futures, которые завершились (выполнились или были отменены) до завершения ожидания. Второе множество, называемоеnot_done, содержит незавершённые futures.timeout можно использовать для управления максимальным количеством секунд ожидания перед возвратом. timeout может быть целым числом или числом с плавающей запятой. Если timeout не указан или
None, время ожидания не ограничено.return_when указывает, когда эта функция должна вернуть результат. Он должен быть одной из следующих констант:
Константа Описание FIRST_COMPLETEDФункция вернёт результат, когда любой future завершится или будет отменён. FIRST_EXCEPTIONФункция вернёт результат, когда любой future завершится, возбудив исключение. Если ни один future не возбудит исключение, это эквивалентно ALL_COMPLETED.ALL_COMPLETEDФункция вернёт результат, когда все future завершатся или будут отменены.
-
concurrent.futures.as_completed(fs, timeout=None)¶ Возвращает итератор по экземплярам
Future(возможно, созданным разными экземплярамиExecutor), заданным в fs, который генерирует futures по мере их завершения (выполнения или отмены). Любые futures, заданные в fs, которые дублируются, будут возвращены один раз. Futures, завершившиеся до вызоваas_completed(), будут выданы первыми. Возвращённый итератор возбуждаетconcurrent.futures.TimeoutError, если вызывается__next__()и результат недоступен через timeout секунд после исходного вызоваas_completed(). timeout может быть целым числом или числом с плавающей запятой. Если timeout не указан или равенNone, время ожидания не ограничено.
См. также
- PEP 3148 – futures - execute computations asynchronously
- Предложение, которое описывало эту возможность для включения в стандартную библиотеку Python.
17.4.6. Классы исключений¶Exception classes
-
exception
concurrent.futures.CancelledError¶ Возникает при отмене future.
-
exception
concurrent.futures.TimeoutError¶ Возбуждается, когда операция с future превышает заданный тайм-аут.
-
exception
concurrent.futures.process.BrokenProcessPool¶ Производный от
RuntimeError, этот класс исключения возбуждается, когда один из рабочих процессовProcessPoolExecutorзавершился некорректно (например, если он был убит извне).Новое в версии 3.3.