nodejs之多进程

本文探讨了Node.js的单线程特性及其在CPU密集型任务中的局限性,介绍了如何利用`child_process`模块创建多进程以解决这一问题。通过实例展示了如何建立和管理子进程,以及使用Cluster模块实现简单的主从模式,提高应用的稳定性和效率。总结指出,多进程分工合作如同团队协作,能显著提升整体性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近感觉压力有点大,来看看nodejs的书,好让自己轻松一下。


正如标题所言,这篇文章写的是关于nodejs进程方面的知识。众所周知,nodejs是单线程的额,在编程方面有着得天独厚的先天优势,可以让我们省去了并发编程所带来的种种苦恼,基于事件驱动的它,面对着io高并发,可以做得很好,但是,有一点是出于劣势的--------面对cpu密集型的情况,可能会导致阻塞,还会浪费空余的cpu。是不是感到很可惜,美中不足啊。不怕不怕啦,多进程来啦!!!!


子进程间通讯

模块“child_process”可以给我们带来多线程。废话少说,代码最实际

//parent.js
var cp = require('child_process');
var n = cp.fork('./sub.js');

n.on('message', function(data) {
  console.log(data.foo);
});

n.send({hello:'world'});

//sub.js
process.on('message', function(m) {
  console.log(m.hello);
});

process.send({foo:'bar'});
有两个文件,parent.js是父进程,sub.js是被创建的子进程。意思很明显,子进程监听父进程发来的消息,同时,它也主动发消息给父进程。至于父进程的话,也是同一意图。猜猜以上会输出什么,貌似令人迷惑。迷惑就对了,事实上,我也迷惑。


---------------------------------集群之路-------------------------------------

下面我们可以来模仿一下集群。一个主进程的话,可以创建和管理众多的子进程。一个稳定的集群,当有任务来的时候,可以分发给自己的子进程去完成。当子进程有种种错误导致崩溃的时候,主进程可以让它重启。准确来说,是再生成另外一个进程。下面,上代码

//master.js
var fork = require('child_process').fork;
var cpus = require('os').cpus();

//创建服务器并监听
var server = require('net').createServer();
server.listen(41234);

var workers = {};
var createWorker = function() {
  //创建子进程
  var worker = fork('./workerall.js');
  
  //退出时记得要重启
  worker.on('exit', function() {
    console.log('worker '+ worker.pid + ' exited');
	delete workers[worker.pid];
	createWorker();  //重启
  });
  worker.send('server', server);
  workers[worker.pid];
  console.log('create worker. pid: ' +worker.pid);
};

//新建好多个线程
for (var i =0; i<cpus.length; i++) {
  createWorker();
}

//自己结束,子进程一起屎
process.on('exit', function(){
  for(var pid in workers) {
    workers[pid].kill();
  }
});




上面的代码意思相当容易懂。首先是创建cpu核个子进程,让他们先工作起来。当子进程退出的时候,及时再生成一个子进程,保证系统的稳定。

下面是子进程代码

//workerall
var http = require('http');
//创建服务器
var server = http.createServer(function(req, res) {
  res.writeHead(200);
  res.end('handle by pid:' +process.pid);
});

var worker;
process.on('message', function(m, tcp) {
  if(m==='server') {
    worker = tcp;
	worker.on('connection', function(socket) {
	  worker.emit('connect', socket);
	});
  }
});

//捕获错误
process.on('uncaughtException', function(err) {
  //停止接受新的连接
  worker.close(function() {
    //所有已经断开了,是时候退出了
	process.exit(1);
  });
});

子进程一旦崩溃,立刻退出,父进程那边会监测到,然后再生成一个,保证系统的稳定。但是,我们可以发现上面代码有着一点小问题。在子进程是在完全退出之后才会让父进程另外再行动,这给我们带来一定的延迟效果,若所有子进程都是这样的话,到时候会没人工作了,所以,为了杜绝此情况,我们可以让子进程在准备退出之际,就生成另外一个,那要怎么做呢?很明显,可以采用消息通知。跟“老板”说清楚之后才辞职,不然突然离开会让人感觉很不好。于是乎,我们其中一段代码修改如下:

//子进程
//捕获错误
process.on('uncaughtException', function(err) {

  process.send({act:'suicide'});
  //停止接受新的连接
  worker.close(function() {
    //所有已经断开了,是时候退出了
	process.exit(1);
  });
});
代码process.send({act:'suicide'});发送消息给父进程。父进程相应代码修改如下:

var createWorker = function() {
  //创建子进程
  var worker = fork('./workerall.js');
  //启动新的子进程
  worker.on('message', function(msg) {
    if(msg.act==='suicide') {
	  createWorker(); //重启
	}
  });
  //退出时记得要重启
  worker.on('exit', function() {
    console.log('worker '+ worker.pid + ' exited');
	delete workers[worker.pid];
  });
  worker.send('server', server);
  workers[worker.pid];
  console.log('create worker. pid: ' +worker.pid);
};

监控子进程发送的消息,若是将要“离开”了,就先“招聘”一个进程替代它。好了,事已至此,似乎已经比较稳定了。然而这里还有一个小小的问题。我是没有发现的,看了书才知道,哦,有这么一回事,真是活到老学到老。是这样样的,有可能我们的连接是长连接,不是HTTP的短链接。等待长连接断开可能需要较长的时间。为此,为已有的连接的断开设置一个超时时间是必要的,在限定的时间里强制退出。代码如下:

//捕获错误
process.on('uncaughtException', function(err) {

  process.send({act:'suicide'});
  //停止接受新的连接
  worker.close(function() {
    //所有已经断开了,是时候退出了
	process.exit(1);
  });
  
  //设置超时(5秒)
  setTimeout(function() {
    process.exit();
  }, 5000);
});

限定的时间是5秒钟,若不退出,则强制退出,不然浪费资源。


---------------------------------------------我是一个分割线,表打我------------------------------------

好了,今天到这里了,还有一点,Cluster,这个东东,官网有详细介绍,这里不多说了。有点累。


总结

通过这个学习,我感觉自己的知识还是挺薄弱的。不过也好,学到不少东西。

node的单线程是相当薄弱的,既不能好好利用空余的cpu,又不足够稳定。集群就不一样了,通过简单的主从模式,可以提高不只是一个档次。每个进程有自己相应的责任,各自分工合作,并且做好,这样,一个个简简单单的东西,会变得好强大。

在现实中也一样,团队里面的人各司其职,并且认真投入,往往会有意想不到的效果。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值