Node.js事件循环与性能优化
理解事件循环是掌握Node.js的关键。Node.js的单线程模型通过事件循环实现高并发,但也带来了独特的性能挑战。本文将深入解析事件循环机制,并介绍Node.js性能优化的实用技巧。
一、事件循环机制
// 事件循环阶段
// ┌──────────────────────────┐
// ┌─│ timers │ 定时器:setTimeout, setInterval
// │ └──────────┬───────────────┘
// │ ┌──────────┴───────────────┐
// │ │ pending callbacks │ 系统级回调
// │ └──────────┬───────────────┘
// │ ┌──────────┴───────────────┐
// │ │ idle, prepare │ 内部使用
// │ └──────────┬───────────────┘
// │ ┌──────────┴───────────────┐
// │ │ poll │ I/O回调
// │ └──────────┬───────────────┘
// │ ┌──────────┴───────────────┐
// │ │ check │ setImmediate
// │ └──────────┬───────────────┘
// │ ┌──────────┴───────────────┐
// │ │ close callbacks │ 关闭事件
// │ └──────────────────────────┘
// 执行顺序示例
setTimeout(function() { console.log("timeout"); }, 0);
setImmediate(function() { console.log("immediate"); });
process.nextTick(function() { console.log("nexttick"); });
// 输出:nexttick → timeout → immediate(大多数情况)
二、避免阻塞事件循环
// 错误:同步CPU密集操作阻塞事件循环
app.get("/compute", function(req, res) {
var result = heavyComputation(10000000); // 阻塞!
res.json(result);
});
// 正确:使用Worker Threads
var { Worker } = require("worker_threads");
app.get("/compute", function(req, res) {
var worker = new Worker("./compute.js", {
workerData: { count: 10000000 }
});
worker.on("message", function(result) {
res.json(result);
});
worker.on("error", function(err) {
res.status(500).json({ error: err.message });
});
});
// 或者分片处理
async function processInChunks(data, chunkSize) {
for (var i = 0; i < data.length; i += chunkSize) {
var chunk = data.slice(i, i + chunkSize);
processChunk(chunk);
// 让出事件循环
await new Promise(function(resolve) { setImmediate(resolve); });
}
}
三、内存优化
// 监控内存使用
var used = process.memoryUsage();
console.log({
rss: Math.round(used.rss / 1024 / 1024) + "MB", // 常驻内存
heapUsed: Math.round(used.heapUsed / 1024 / 1024) + "MB", // 堆使用
external: Math.round(used.external / 1024 / 1024) + "MB", // C++对象
});
// 内存泄漏常见原因
// 1. 全局变量 - 避免意外全局
// 2. 闭包引用 - 注意大对象引用
// 3. 事件监听器 - 未移除的监听器
// 限制监听器数量
emitter.setMaxListeners(20);
// Stream处理大文件 - 避免全部读入内存
var fs = require("fs");
var readline = require("readline");
var rl = readline.createInterface({
input: fs.createReadStream("large-file.csv")
});
rl.on("line", function(line) {
// 逐行处理
});
四、集群模式
var cluster = require("cluster");
var numCPUs = require("os").cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on("exit", function(worker) {
console.log("Worker " + worker.process.pid + " died");
cluster.fork(); // 自动重启
});
} else {
// Worker进程
require("./app");
}
Node.js的性能优化需要深入理解事件循环和V8引擎的工作方式。关键是避免阻塞事件循环、合理管理内存、充分利用多核CPU。建议建立完善的监控体系,及时发现和解决性能瓶颈。