Модуль concurrent.futures

Модуль concurrent.futures предоставляет высокоуровневый интерфейс для работы с процессами и потоками. При этом и для потоков, и для процессов используется одинаковый интерфейс, что позволяет легко переключаться между ними.

Если сравнивать этот модуль с threading или multiprocessing, то у него меньше возможностей, но с concurrent.futures работать проще и интерфейс более понятный.

Модуль concurrent.futures позволяет решить задачу запуска нескольких потоков/процессов и получения из них данных. Для этого в модуле используются два класса:

  • ThreadPoolExecutor - для работы с потоками
  • ProcessPoolExecutor - для работы с процессами

Оба класса используют одинаковый интерфейс, поэтому достаточно разобраться с одним и затем просто переключиться на другой при необходимости.

Создание объекта Executor на примере ThreadPoolExecutor:

executor = ThreadPoolExecutor(max_workers=5)

После создания объекта Executor, у него есть три метода: shutdown, map и submit. Метод shutdown отвечает за завершение потоков/процессов, а методы map и submit за запуск функций в разных потоках/процессах.

Примечание

На самом деле, map и submit могут запускать не только функции, а и любой вызываемый объект. Однако далее будут рассматриваться только функции.

Метод shutdown указывает, что объекту Executor надо завершить работу. При этом, если методу shutdown передать значение wait=True (значение по умолчанию), он не вернет результат пока не завершатся все функции, которые запущены в потоках. Если же wait=False, метод shutdown завершает работу мгновенно, но при этом сам скрипт не завершит работу пока все функции не отработают.

Как правило, метод shutdown не используется явно, так как при создании объекта Executor в менеджере контекста, метод shutdown автоматически вызывается в конце блока with c wait равным True.

with ThreadPoolExecutor(max_workers=5) as executor:
    ...

Так как методы map и submit запускают какую-то функцию в потоках или процессах, в коде должна присутствовать, как минимум, функция которая выполняет одно действие и которую надо запустить в разных потоках с разными аргументами функции.

Например, если необходимо пинговать несколько IP-адресов в разных потоках, надо создать функцию, которая будет пинговать один IP-адрес, а затем запустить эту функцию в разных потоках для разных IP-адресов с помощью concurrent.futures.