【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 密集型任务
相关推荐
胖子不胖几秒前
浅析cubic-bezier
前端
希望永不加班4 分钟前
SpringBoot 主启动类解释:@SpringBootApplication 到底做了什么
java·spring boot·后端·spring
reasonsummer5 分钟前
【办公类-133-02】20260319_学区化展示PPT_02_python(图片合并文件夹、提取同名图片归类文件夹、图片编号、图片GIF)
前端·数据库·powerpoint
一只叫煤球的猫7 分钟前
为什么不用 RAG 做记忆系统 ——压缩上下文与 memory.md 的架构选择
人工智能·后端·ai编程
智能工业品检测-奇妙智能13 分钟前
国产化系统的性价比对比
人工智能·spring boot·后端·openclaw·奇妙智能
胡耀超20 分钟前
Web Crawling 网络爬虫全景:技术体系、反爬对抗与全链路成本分析
前端·爬虫·python·网络爬虫·数据采集·逆向工程·反爬虫
编码忘我24 分钟前
java强引用、软引用、弱引用、虚引用
后端
阿明的小蝴蝶24 分钟前
记一次Gradle环境的编译问题与解决
android·前端·gradle
Ruihong26 分钟前
【VuReact】轻松实现 Vue 到 React 路由适配
前端·react.js
山_雨27 分钟前
startViewTransition
前端