Перейти к содержанию

Начало урока

Потоки-воркеры (Worker Threads)

Выполняйте вычислительную нагрузку параллельно, не блокируя цикл событий

Главная идея: Node выполняет ваш JavaScript в одном главном потоке. Это идеально для задач, насыщенных вводом-выводом, но долгое синхронное вычисление блокирует всё -- ни один запрос не обслуживается, ни один таймер не срабатывает -- пока оно не завершится. Модуль 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 минут, вся очередь встанет. Поток-воркер -- это второй кассир в подсобке: вы передаёте ему заказ, он готовит, а передний кассир продолжает обслуживать всех остальных.

Продолжите этот урок на YourAIZone

В полном уроке — объяснение целиком, разобранные примеры, частые ошибки, тесты с мгновенной проверкой и ИИ-репетитор. Начните сразу как гость или создайте аккаунт, чтобы сохранять прогресс.

В полном уроке

  • Объяснение целиком
  • Разобранные примеры
  • Частые ошибки и как их избежать
  • Тестовые вопросы: 15
  • ИИ-репетитор, который отвечает на вопросы по теме
  • Отслеживание прогресса для ученика, родителей и учителя