← Назад к вопросам

Как реализовать многопоточность используя userland в Node.js?

2.8 Senior🔥 91 комментариев
#Node.js и JavaScript#Архитектура и паттерны#Кэширование и производительность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Многопоточность в userland Node.js

Многопоточность в Node.js реализуется через несколько подходов на уровне приложения (userland), так как сам Node.js работает в single-threaded event loop.

Основные методы

1. Worker Threads (встроенное решение)

Это официальный способ для CPU-bound задач:

const { Worker } = require('worker_threads');
const path = require('path');

// Создание рабочего потока
const worker = new Worker(path.join(__dirname, 'worker.js'));

// Отправка данных
worker.postMessage({ data: 'hello' });

// Получение результата
worker.on('message', (result) => {
  console.log('Результат:', result);
});

worker.on('error', reject);
worker.on('exit', (code) => {
  if (code !== 0) reject(new Error(`Worker exited with code ${code}`));
});

В worker.js:

const { parentPort } = require('worker_threads');

parentPort.on('message', (msg) => {
  const result = msg.data.toUpperCase();
  parentPort.postMessage(result);
});

2. Cluster Module (для масштабирования)

Используется для распределения нагрузки между процессами:

const cluster = require('cluster');
const os = require('os');
const http = require('http');

if (cluster.isMaster) {
  // Мастер процесс
  const numCPUs = os.cpus().length;
  
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  
  cluster.on('exit', (worker) => {
    console.log(`Worker ${worker.process.pid} умер`);
    cluster.fork();
  });
} else {
  // Рабочий процесс
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('Hello World\n');
  }).listen(8000);
}

3. Thread Pool (пула потоков)

Управление пулом рабочих потоков для многозадачности:

const { Worker } = require('worker_threads');

class ThreadPool {
  constructor(size) {
    this.workers = [];
    this.queue = [];
    
    for (let i = 0; i < size; i++) {
      const worker = new Worker('./worker.js');
      worker.busy = false;
      this.workers.push(worker);
    }
  }
  
  execute(task) {
    return new Promise((resolve, reject) => {
      const availableWorker = this.workers.find(w => !w.busy);
      
      if (availableWorker) {
        availableWorker.busy = true;
        availableWorker.once('message', (result) => {
          availableWorker.busy = false;
          resolve(result);
          this.processQueue();
        });
        availableWorker.postMessage(task);
      } else {
        this.queue.push({ task, resolve, reject });
      }
    });
  }
  
  processQueue() {
    if (this.queue.length === 0) return;
    const { task, resolve, reject } = this.queue.shift();
    this.execute(task).then(resolve).catch(reject);
  }
}

Когда использовать

  • Worker Threads: CPU-intensive операции (обработка изображений, крипто, вычисления)
  • Cluster: Масштабирование HTTP сервера на много ядер
  • Async/Await + Event Loop: I/O операции (БД, API запросы) — не требуют отдельных потоков

Best Practices

  • Переиспользуй workers вместо создания новых
  • Ограничивай размер очереди
  • Обрабатывай ошибки и graceful shutdown
  • Для I/O операций используй асинхронный код, не workers