要一直走下去

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

nodejs天生是单线程的,因此不能在nodejs中启动多个线程,但可以实现多进程

process模块常用方法

process.env 返回包含用户环境的对象,可设置环境变量,例如Process.env.NODE_ENV

 

 打印process.env:

process.pid     返回进程的pid
process.platform       返回当前进程的操作系统平台
process.title       获取或指定进程名称
process.on(‘uncaughtException’,cb)        捕获异常信息
process.on(‘exit’,cb)          监听进程退出
process.cwd()             返回当前进程的工作目录
process.uptime()             返回当前进程运行时间,单位秒

 

使用child_process模块创建子进程 

有四种方式可供选择:

1、child_process.spawn():能运行所有命令;没有回调;

2、child_process.exec():能运行所有命令;有回调,回调中打印;衍生shell运行慢

3、child_process.execFile():能运行所有命令;有回调,回调中打印;不会衍生shell运行快

4、child_process.fork() : 只能运行node命令;没有回调可以直接打印;

演示spawn:访问/compute路径打印子进程work.js的输出结果

 主程序

const http = require('http')
const {spawn} = require('child_process')

const server = http.createServer((req,res)=>{
  if(req.url== '/compute'){
    const work = spawn('node',['work.js'])
    //监听子进程的标准输出流,获取子进程的打印结果
    work.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });
  }
})

server.listen(3000,()=>{
  console.log('listen sucess')
})

work.js

process.title = '计算'

let sum = 0;
for(let i = 0;i<1e10;i++){
  sum += i
}

console.log(sum)
//console.error("出错")

演示exec:访问/compute路径打印子进程work.js的输出结果

 主程序:

const http = require('http')
const {exec} = require('child_process')

const server = http.createServer((req,res)=>{
  if(req.url== '/compute'){
     exec('node work.js',(err,stdout,stderr)=>{
       if(err) throw err
       console.log(stdout)  //直接打印
     })
  }
})

server.listen(3000,()=>{
  console.log('listen sucess')
})

演示execFile:访问/compute路径打印子进程work.js的输出结果

主程序

const http = require('http')
const {execFile} = require('child_process')

const server = http.createServer((req,res)=>{
  if(req.url== '/compute'){
    //execFile类似于exec,但默认情况下不会衍生shell,比exec稍微高效一点
     execFile('node',['work.js'],(err,stdout,stderr)=>{
       if(err) throw err
       console.log(stdout)  //不用on data直接获取
       console.log(stderr)
     })
  }
})

server.listen(3000,()=>{
  console.log('listen sucess')
})

演示fork:访问/compute路径打印子进程work.js的输出结果

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

const server = http.createServer((req,res)=>{
  if(req.url== '/compute'){
    // fork只能运行node命令,不能运行其他的方法。跟直接运行js代码一样,不需要使用stdout来输出,直接就打印在控制台了
    fork('work.js')
  }
})

server.listen(3000,()=>{
  console.log('listen sucess')
})

 

使用cluster模块创建子进程

 

主进程做分发,工作进程是真正干事的

/**
* cluster模块支持两种分发连接的方法:
* 第一种:循环法(除Windows外所有平台的默认方法),由主进程负责监听端口,接收新连接后再将连接循环分发给工作进程,在分发中使用了一些内置技巧防止工作进程任务过载
* 第二种:主进程创建监听socket后发送给感兴趣的工作进程,由工作进程负责直接接收连接
*/

 

cluster创建工作进程的案例:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;  //获取CPU的核数,一般有多少个CPU就创建多少个工作进程

//如果该进程是主进程,isMaster=true。这是由process.env.NODE_UNIQUE_ID决定,如果NODE_UNIQUE_ID未定义,则isMaster=true
if (cluster.isMaster) {
  console.log(`主进程 ${process.pid} 正在运行`);

  // 创建工作进程。
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  //监听进程的退出
  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 为什么不存在端口占用的问题???cluster模块支持两种分发连接的方法,这里用的是第一种
  // 工作进程可以共享任何 TCP 连接。 在本例子中,共享的是 HTTP 服务器。
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('你好世界\n');
  }).listen(8000);

  console.log(`工作进程 ${process.pid} 已启动`);
}

 

 进程间通信

 进程间通信的原理:

父进程在实际创建子进程之前,会创建IPC通道并监听它,然后才真正的创建出子进程。此过
程中会通过环境变量(NODE_CHANNEL_FD)告诉子进程这个IPC通道的文件描述符。子进
程在启动的过程中,根据文件描述符连接这个IPC通道,从而完成父子进程之间的连接。

 

 代码示例:

子进程——计算出结果后,进入监听,等待父进程的通知,再将结果发送给父进程

父进程——计算出结果后,进入监听,等待子进程的结果

主程序:
const http = require('http')
const {fork} = require('child_process')

const server = http.createServer((req, res) => {
    if (req.url === '/compute') {
        res.writeHead(200, {'content-type': 'application/json;charset=UTF-8'})
        //fork子进程
        const work = fork('work.js')
        work.send('发送给子进程的信息')
        work.on('message', data => {
            res.end('父进程接收子进程的消息:' + data)
        })
    }
})

server.listen(3000, () => {
    console.log('listen sucess')
})

work.js

process.title = '计算'

let sum = 0;
for(let i = 0;i<100;i++){
  sum += i
}

process.on('message',(data)=>{
  console.log('接收父进程的消息:'+data)
  process.send(sum)
})

运行结果:

 

 

 

 

 

 

posted on 2022-07-16 22:58  要一直走下去  阅读(1328)  评论(0)    收藏  举报