理解NodeJS多进程

序言

一次面试中,我提到自己用过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 = 

你可能感兴趣的:(node.js)