Node.js事件循环与性能优化


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。建议建立完善的监控体系,及时发现和解决性能瓶颈。


0.050238s