Потоки-воркеры (Worker Threads)
Выполняйте вычислительную нагрузку параллельно, не блокируя цикл событий
worker_threads позволяет перенести такое вычисление в отдельный поток со своим циклом событий и своим изолятом V8, так что главный поток остаётся отзывчивым.
- объяснить, почему вычислительная работа блокирует цикл событий, а ввод-вывод -- нет;
- создать
Workerи обмениваться данными черезpostMessage/workerData; - использовать передаваемые объекты (transferable) для перемещения буферов без копирования;
- разделять память между потоками с помощью
SharedArrayBufferиAtomics; - правильно выбирать между потоками-воркерами, cluster и child_process.
1. Почему циклу событий нужна помощь
Вы уже знаете, что цикл событий сохраняет отзывчивость Node, никогда не блокируясь на вводе-выводе: запрос к базе данных или чтение файла передаётся ОС (или потоку libuv), а ваш колбэк выполняется позже. Загвоздка в том, что сам ваш JavaScript всё равно выполняется в одном потоке. Если функция тратит 3 секунды на хеширование пароля с большим фактором стоимости, изменение размера 40-мегапиксельного изображения или разбор огромного CSV, ничто другое в этом потоке не может выполняться эти 3 секунды.
// This blocks the whole process for as long as it runs
function fib(n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }
app.get('/slow', (req, res) => res.json({ result: fib(45) })); // ~seconds
// Every other request now waits behind this one CPU-bound call.
Важное различие: работа, ограниченная вводом-выводом (ожидание диска, сети, сокетов), уже параллельна, потому что ожидание происходит вне вашего потока. Проблема -- в работе, ограниченной процессором (чистые вычисления), потому что она монополизирует единственный поток, выполняющий JavaScript. Разбиение её на фрагменты через setImmediate немного помогает задержке, но тратит реальное время впустую и хлопотно. Настоящее решение -- второй поток.
Аналогия. Главный поток -- это один кассир, который блестяще передаёт заказы на кухню и идёт дальше. Но если клиент попросит кассира лично приготовить блюдо за 20 минут, вся очередь встанет. Поток-воркер -- это второй кассир в подсобке: вы передаёте ему заказ, он готовит, а передний кассир продолжает обслуживать всех остальных.