Node.js 异步编程与并发模型

深入 Node.js 异步编程:Event Loop 事件循环阶段详解、Promise/async-await、Worker Threads 多线程、Cluster 多进程与并发性能优化。

1. Event Loop 详解

1.1 事件循环阶段

    ┌───────────────────────────┐
┌─>│           timers            │  ← setTimeout/setInterval
│  └─────────────┬─────────────┘
│  ┌─────────────▼─────────────┐
│  │     pending callbacks     │  ← I/O callbacks deferred
│  └─────────────┬─────────────┘
│  ┌─────────────▼─────────────┐
│  │       idle, prepare       │  ← internal
│  └─────────────┬─────────────┘
│  ┌─────────────▼─────────────┐
│  │           poll            │  ← retrieve new I/O events
│  │     (阻塞等待 I/O)         │
│  └─────────────┬─────────────┘
│  ┌─────────────▼─────────────┐
│  │           check           │  ← setImmediate
│  └─────────────┬─────────────┘
│  ┌─────────────▼─────────────┐
│  │      close callbacks      │  ← socket.on('close')
│  └───────────────────────────┘
│
└─────────────────────────────────┘
     每次循环 = 一个 tick
     microtask 队列(process.nextTick / Promise)在每阶段后执行

1.2 执行顺序示例

console.log('1');

setTimeout(() => console.log('2'), 0);
setImmediate(() => console.log('3'));

Promise.resolve().then(() => console.log('4'));
process.nextTick(() => console.log('5'));

console.log('6');

// 输出: 1, 6, 5, 4, 2, 3
// 解释:
//   1. 同步代码: 1, 6
//   2. nextTick: 5
//   3. Promise microtask: 4
//   4. timers: 2 (setTimeout)
//   5. check: 3 (setImmediate)
// 注意: setTimeout(0) 和 setImmediate 顺序取决于 poll 阶段是否有 I/O

1.3 阻塞 Event Loop 的危险

// ❌ 同步计算阻塞(CPU 密集型)
app.get('/fib/:n', (req, res) => {
    const n = parseInt(req.params.n);
    const result = fibonacci(n);  // 同步递归,阻塞事件循环!
    res.json({ result });
});

// ✅ 方案 1:拆分计算(setImmediate)
function fibAsync(n, callback) {
    let a = 0, b = 1;
    function step() {
        if (n <= 0) return callback(a);
        [a, b] = [b, a + b];
        n--;
        setImmediate(step);  // 让出事件循环
    }
    step();
}

// ✅ 方案 2:Worker Threads
const { Worker } = require('worker_threads');
app.get('/fib/:n', async (req, res) => {
    const worker = new Worker('./fib-worker.js', {
        workerData: parseInt(req.params.n)
    });
    worker.on('message', result => res.json({ result }));
});

2. Worker Threads

Node.js 10.5+ 引入 Worker Threads,实现了真正的多线程并行计算。

const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

// 主线程
if (isMainThread) {
    const worker = new Worker(__filename, {
        workerData: { start: 1, end: 1000000 }  // 传递数据给 Worker
    });
    
    worker.on('message', result => console.log('Sum:', result));
    worker.on('error', err => console.error(err));
    worker.on('exit', code => console.log('Worker exited'));
} else {
    // Worker 线程
    const { start, end } = workerData;
    let sum = 0;
    for (let i = start; i <= end; i++) sum += i;
    parentPort.postMessage(sum);
}

Worker vs Cluster

特性Worker ThreadsCluster
目的CPU 密集型并行网络 I/O 扩展
内存共享 ArrayBuffer独立的进程内存
适用计算、图片处理Web 服务器负载均衡

3. Cluster 多进程

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

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} died, restarting...`);
        cluster.fork();
    });
} else {
    http.createServer((req, res) => {
        res.writeHead(200);
        res.end(`Worker ${process.pid} handled\n`);
    }).listen(3000);
}

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「nodejs」更多文章

  1. Node.js ORM 深度对比:Prisma、TypeORM、Sequelize 与 Drizzle
  2. Node.js 设计模式与最佳实践:从 SOLID 到六边形架构
  3. Node.js 高级测试策略:从单元测试到混沌工程的完整实践