Node.js 如何处理 cpu 密集型问题

总所周知,Node.js 中的异步 I/O 编程特点,非常适合处理 I/O 密集型的情况,但是由于 javascript 单线程的特点,使 Node.js 对于处理 CPU 密集型问题却成为了 Node.js 的弱项,如果遇到 CPU 密集型问题,我们该怎么处理呢,下面我总结了几个相关处理方法:

创建子进程:

Node.js 的 child_process 模块提供了创建工作子进程的方式来弥补单线程的缺点,使其尽量不要堵塞整个线程的运行,一共提供了如下四个函数:

  • spawn:执行简单命令,不支持 callback 函数。
var child = require('child_process');
var du = child.spawn('du', ['-sh', '/disk1']);
du.stdout.on('data', function (data) {
    console.log('stdout: ' + data);
});
du.stderr.on('data', function (data) {
    console.log('stderr: ' + data);
});
du.on('exit', function (code) {
    console.log('child process exited with code ' + code);
});

  • exec:exec函数是对spawn的一种友好封装,增加Shell命令解析,可以直接嵌入复杂的命令,支持callback函数。
var childProcess = require('child_process');

var ls = childProcess.exec('cat *.js | wc', function (error, stdout, stderr) {
   if (error) {
     console.log(error.stack);
     console.log('Error code: '+error.code);
   }
   console.log('Child Process STDOUT: '+stdout);
});

  • execFile:execFile函数会直接执行特定的程序,参数作为数组传入,不会被bash解释,因此具有较高的安全性。execFile与spawn的参数相似,也需要分别指定执行的命令和参数,但可以接受一个回调函数,与exec的回调函数相同。
var childProcess = require('child_process');
var path = ".";
childProcess.execFile('/bin/ls', ['-l', path], function (err, result) {
    console.log(result)
});

  • fork:fork 衍生一个新的 Node.js进程,会在父进程与子进程之间建立一个IPC通信管道。每个进程都有自己的内存,使用自己的 V8 实例。 由于需要额外的资源分配,因此不推荐衍生大量的 Node.js 进程。
let fork = require('child_process').fork;
let path = require('path');

module.exports = function (content, filePath) {
    return new Promise(function (res, rej) {
        let task = fork(path.resolve(__dirname, 'exportExcel.js'));
        task.send({
            content: content,
            filePath: filePath
        });
        task.on('close', res);
        task.on('error', rej);
    });
};

process.on('message', function (opt) {
    let XLSX = require('xlsx');
    /*****
    excel表格生成计算过程....
    ******/
    XLSX.writeFile(wb, opt.filePath);
    process.exit(0);
});

console.log(ctx.query);
console.log(ctx.request.query);

ctx.body = {a: 1};
ctx.response.body = {a: 1};
鉴于频繁的创建子进程和关闭子进程,资源消耗比较大,不建议在代码里大量使用子进程的方式去实现。对于部分 CPU 消耗比较大函数,可以在子进程里实现,不要堵塞主进程的正常执行。
部署多个实例

同一台机器上部署多个实例,利用负载均衡管理工具来实现请求的均匀分发,这样每个实例使用一个 CPU,能提高多核 CPU 的利用率,常见的 Node.js 多实例管理工具如下:

  • PM2 : 专门为 Node 服务的多进程管理工具
  • docker: 通过 docker 相关工具部署多个实例
  • nginx: 专门负责负载均衡的高可用工具
抽取子服务模块

如果确定有些功能 CPU 消耗特别高,且功能比较独立,我们完全可以将其独立出来,实现一个子服务,通过 rpc 方式调用。减少主服务的压力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值