【Node】Node.js 多进程与多线程:Cluster 与 Worker Threads 入门

前言

在 Node.js 开发中,处理 CPU 密集型任务和提升应用性能是常见需求。

今天我们来深入理解 Node.js 提供的两种并发处理方案:Cluster 模块和 Worker Threads 模块。

☺️ 这边要求阅读本文的新手小伙伴要有一个印象:【Cluster】 与【进程】相关,【Worker Threads】 与【线程】相关
小贴士 📚:

✨Cluster 的中文意思是集群 ✨Worker Threads 的中文意思是工作线程

官方定义解析

Node.js 官方文档指出:

"Node.js 进程的集群可用于运行多个 Node.js 实例,这些实例可以在其应用程序线程之间分配工作负载。当不需要进程隔离时,请改用 worker_threads 模块,它允许在单个 Node.js 实例中运行多个应用程序线程。"

核心概念解释

进程(Process)

  • 拥有【独立内存空间】的程序实例
  • 相当于一个独立的应用程序
  • 进程间相互隔离,一个崩溃不会影响其他进程

线程(Thread)

  • 进程内的执行单元
  • 共享进程的内存空间
  • 线程间可以更高效地通信

两种方案的对比

Cluster 模块(多进程)

javascript 复制代码
const cluster = require('cluster')
const os = require('os')

if (cluster.isPrimary) {
    // 主进程:创建工作进程
    for (let i = 0; i < os.cpus().length; i++) {
        cluster.fork()
    }
} else {
    // 工作进程:启动服务器
    require('./server.js')
}

适用场景

  • HTTP 服务器负载均衡
  • 需要高隔离性的任务
  • 利用多核 CPU 处理并发请求

特点

  • ✅ 进程隔离,稳定性高
  • ✅ 充分利用多核 CPU
  • ❌ 内存开销较大
  • ❌ 进程间通信成本较高

Worker Threads 模块(多线程)

javascript 复制代码
const {Worker} = require('worker_threads')

function runWorker(data) {
    return new Promise((resolve, reject) => {
        const worker = new Worker(
            `
      const { parentPort } = require('worker_threads');
      parentPort.on('message', (data) => {
        // 执行计算密集型任务
        const result = heavyCalculation(data);
        parentPort.postMessage(result);
      });
    `,
            {eval: true}
        )

        worker.on('message', resolve)
        worker.on('error', reject)
        worker.postMessage(data)
    })
}

适用场景

  • CPU 密集型计算任务
  • 图像/视频处理
  • 大数据分析
  • 加密解密操作

特点

  • ✅ 内存共享,开销较小
  • ✅ 线程间通信高效
  • ❌ 隔离性较差,一个线程崩溃可能影响整个进程
  • ❌ 需要处理线程同步问题

选择指南

什么时候用 Cluster?

  • 构建 Web 服务器,需要处理大量并发连接。其实可以联想到 pm2 的多进程模式 ------ 经过了解,得知 PM2 的集群模式(pm2 start app.js -i 4)在底层正是使用了 Node.js 的 Cluster 模块 来实现的。
  • 任务需要高度的稳定性和隔离性
  • 希望充分利用多核 CPU 性能

什么时候用 Worker Threads?

  • 需要执行复杂的数学计算或数据处理
  • 任务需要共享大量数据
  • 希望减少内存开销
  • 在单个进程中需要并行处理多个任务

实际应用示例

场景:图像处理服务

javascript 复制代码
// 使用 Worker Threads 处理图像
const {Worker} = require('worker_threads')

class ImageProcessor {
    async processImages(images) {
        const workers = images.map(image => this.createWorker('./image-worker.js', image))

        const results = await Promise.all(workers)
        return results
    }

    createWorker(workerPath, data) {
        return new Promise((resolve, reject) => {
            const worker = new Worker(workerPath, {workerData: data})
            worker.on('message', resolve)
            worker.on('error', reject)
        })
    }
}

场景:高并发 Web 服务

javascript 复制代码
// 使用 Cluster 创建 Web 服务器集群
const cluster = require('cluster')
const http = require('http')
const numCPUs = require('os').cpus().length

if (cluster.isPrimary) {
    console.log(`主进程 ${process.pid} 正在运行`)

    // 衍生工作进程
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork()
    }

    cluster.on('exit', (worker, code, signal) => {
        console.log(`工作进程 ${worker.process.pid} 已退出`)
    })
} else {
    // 工作进程共享同一个端口
    http.createServer((req, res) => {
        res.writeHead(200)
        res.end('你好世界\n')
    }).listen(8000)

    console.log(`工作进程 ${process.pid} 已启动`)
}

性能考量

  1. 内存使用:Worker Threads 通常比 Cluster 更节省内存
  2. 启动速度:线程启动比进程启动更快
  3. 通信成本:线程间通信比进程间通信更高效
  4. 稳定性:Cluster 提供更好的故障隔离

总结

这边简单做个总结 🍃

  • Cluster 适合需要高隔离性和稳定性的 I/O 密集型任务
  • Worker Threads 适合需要高效内存使用的 CPU 密集型任务
相关推荐
烈风2 小时前
011 Rust数组
开发语言·后端·rust
闲人编程2 小时前
使用Celery处理Python Web应用中的异步任务
开发语言·前端·python·web·异步·celery
excel2 小时前
前端读取文件夹并通过 SSH 上传:完整实现方案 ✅
前端
谢尔登3 小时前
【Nest】日志记录
javascript·中间件·node.js
托比-马奎尔3 小时前
Redis7内存数据库
java·redis·后端
双向333 小时前
【征文计划】基于Rokid CXR-M SDK 打造AI 实时会议助手:从连接到自定义界面的完整实践
前端
Lei活在当下3 小时前
【业务场景架构实战】6. 从业务痛点到通用能力:Android 优先级分页加载器设计
前端·后端·架构
你的人类朋友3 小时前
什么是基础设施中间件
前端·后端
知识分享小能手3 小时前
微信小程序入门学习教程,从入门到精通,WXML(WeiXin Markup Language)语法基础(8)
前端·学习·react.js·微信小程序·小程序·vue·个人开发