Пул потоков

Оригинальное название: thread pool

Коротко

Набор заранее запущенных рабочих потоков, которые по очереди берут задачи из общей очереди. Потоки не создаются и не уничтожаются под каждую задачу.

Что такое «Пул потоков»

Создать поток — операция не бесплатная: системе нужно выделить память под стек, зарегистрировать исполнителя в планировщике. Если на каждую мелкую задачу запускать новый поток, накладные расходы съедят выигрыш от параллельности, а при всплеске нагрузки потоков станет столько, что процессор будет больше переключаться между ними, чем работать. Пул решает обе проблемы: исполнителей фиксированное число, они живут долго, а поступающая работа ждёт своей очереди.

Устройство пула

  1. При старте пул создаёт N рабочих потоков.
  2. Задачи складываются в очередь.
  3. Свободный поток берёт задачу, выполняет её и возвращается за следующей.
  4. Если очередь пуста, потоки ждут, не нагружая процессор.

Готовые реализации есть почти везде: ExecutorService в Java, ThreadPoolExecutor в Python, пул потоков в .NET. В Node.js JavaScript выполняется в одном потоке, но файловые операции и часть криптографии уходят во внутренний пул библиотеки libuv — по умолчанию в нём четыре потока, размер меняют переменной UV_THREADPOOL_SIZE.

Пример: проверка ссылок на Python

from concurrent.futures import ThreadPoolExecutor
import urllib.request

def check(url):
    with urllib.request.urlopen(url, timeout=10) as r:
        return url, r.status

with ThreadPoolExecutor(max_workers=8) as pool:
    for url, status in pool.map(check, urls):
        print(url, status)

Сотня адресов проверяется восемью потоками: пока одни ждут ответа сети, другие уже отправляют следующие запросы. Обработку ошибок сети в реальном скрипте стоит добавить внутрь check.

Как выбрать размер

Для задач, которые нагружают процессор — сжатие, расчёты, — разумный размер близок к числу ядер: больше потоков не ускорит работу. Для задач, которые в основном ждут сети или диска, потоков можно сделать больше, но тогда ограничением становятся внешний сервис и база данных. Тот же принцип в мире PHP работает на уровне процессов: PHP-FPM держит пул рабочих процессов, и параметр pm.max_children задаёт их предел. Слишком маленький пул — запросы стоят в очереди и сайт отвечает медленно, слишком большой — серверу не хватает памяти.

Обновлено:

Все термины раздела «Backend»

Что будем искать? Например,Продвижение