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 Threads | Cluster |
|---|---|---|
| 目的 | 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);
}
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。