理解NodeJS多进程

本文详细介绍了NodeJS中的多进程概念,包括创建多进程、进程间通信、使用cluster模块进行集群管理以及进程管理工具pm2和egg-cluster。特别讨论了父子进程通信的内置IPC通道、socket、管道和信号等通信方式,以及pm2如何实现后台运行、自动重启和集群支持。
摘要由CSDN通过智能技术生成

序言

一次面试中,我提到自己用过pm2,面试接着问:「那你知道pm2父子进程通信方式吗」。我大概听说pm2有cluster模式,但不清楚父子进程如何通信。面试结束后把NodeJS的多进程重新整理了一下。

对于前端开发同学,一定很清楚js是单线程非阻塞的,这决定了NodeJS能够支持高性能的服务的开发。 JavaScript的单线程非阻塞特性让NodeJS适合IO密集型应用,因为JavaScript在访问磁盘/数据库/RPC等时候不需要阻塞等待结果,而是可以异步监听结果,同时继续向下执行。

但js不适合计算密集型应用,因为当JavaScript遇到耗费计算性能的任务时候,单线程的缺点就暴露出来了。后面的任务都要被阻塞,直到耗时任务执行完毕。

为了优化NodeJS不适合计算密集型任务的问题,NodeJS提供了多线程和多进程的支持。

多进程和多线程从两个方面对计算密集型任务进行了优化,异步和并发

1.异步,对于耗时任务,可以新建一个线程或者进程来执行,执行完毕再通知主线程/进程。

看下面例子,这是一个koa接口,里面有耗时任务,会阻塞其他任务执行。

const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {const url = ctx.request.url;if (url === '/') {ctx.body = 'hello';}if (url === '/compute') {let sum = 0;for (let i = 0; i < 1e20; i++) {sum += i;}ctx.body = `${sum}`;}
});

app.listen(3000, () => {console.log('http://localhost:300/ start')
}); 

可以通过多线程和多进程来解决这个问题。

NodeJS提供多线程模块worker_threads,其中Woker模块用来创建线程,parentPort用在子线程中,可以获取主线程引用,子线程通过parentPort.postMessage发送数据给主线程,主线程通过worker.on接受数据。

//api.js
const Koa = require('koa');
const app = new Koa();

const {Worker} = require('worker_threads');

app.use(async (ctx) => {const url = ctx.request.url;if (url === '/') {ctx.body = 'hello';}if (url === '/compute') {const sum = await new Promise(resolve => {const worker = new Worker(__dirname + '/compute.js');//接收信息worker.on('message', data => {resolve(data);})});ctx.body = `${sum}`;}
})

app.listen(3000, () => {console.log('http://localhost:3000/ start')
});

//computer.js
const {parentPort} = require('worker_threads')
let sum = 0;
for (let i = 0; i < 1e20; i++) {sum += i;
}

//发送信息
parentPort.postMessage(sum); 

下面是使用多进程解决耗时任务的方法,多进程模块child_process提供了fork方法(后面会介绍更多创建子进程的方法),可以用来创建子进程,主进程通过fork返回值(worker)持有子进程的引用,并通过worker.on监听子进程发送的数据,子进程通过process.send给父进程发送数据。

//api.js
const Koa = require('koa');
const app = new Koa();

const {fork} = require('child_process');

app.use(async ctx => {const url = ctx.request.url;if (url === '/') {ctx.body = 'hello';}if (url === '/compute') {const sum = await new Promise(resolve => {const worker = fork(__dirname + '/compute.js');worker.on('message', data => {resolve(data);});});ctx.body = `${sum}`;}
});

app.listen(300, () => {console.log('http://localhost:300/ start');
});

//computer.js
let sum = 0;
for (let i = 0; i < 1e20; i++) {sum += i;
}
process.send(sum); 

2.并发,为了可以更好地利用多核能力,通常会对同一个脚本创建多进程和多线程,数量和CPU核数相同,这样可以让任务并发执行,最大程度提升了任务执行效率。

本文重点讲解多进程的使用。

从实际应用角度,如果我们希望使用多进程,让我们的应用支持并发执行&#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值