今天就跟大家聊聊有关nodejs中怎么实现多进程,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
成都创新互联主营巴彦网站建设的网络公司,主营网站建设方案,成都App定制开发,巴彦h5微信小程序开发搭建,巴彦网站营销推广欢迎巴彦等地区企业咨询
nodjes单线程,在处理http请求的时候一个错误都会导致整个进程的退出,这是灾难级的;
进程是资源分配的最小单位,线程是CPU调度的最小单位
进程--资源分配最小单位,线程--程序咨询最小单位
线程是进程的执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,一个进程由几个线程组成,线程与同属一个进程的其他线程共享进程所拥有的全部资源。
一个进程下面的线程是可以去通信的,共享资源
进程由独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径,线程有自己的堆栈和局部变量,但线程没有嘟嘟的地址空间,一个线程死掉等于整个进程死掉;
谷歌浏览器
进程:一个tab就是一个进程
线程:一个tab又由多个线程组成,渲染线程,js执行线程,垃圾回收,service worker等
node服务
主线程:获取代码,编译执行
编译线程:主线程执行的时候,可以优化代码(v8引擎)
Profiler线程:记录哪些方法耗时,为优化提供支持
其他线程:用于垃圾回收清除工作,因为多个线程,所以可以并行清除
ab是Apache自带的压力测试工具
ab -1000 -c20 '192.168.31.25:8000/'
进程:监听某个端口的http服务
线程:http服务由多个线程组成,比如:
多进程和多线程一般可以结合起来使用
多进程:稳定,安全
多线程:快
对比维度 | 多进程 | 多线程 | 总结 |
---|---|---|---|
数据共享、同步 | 数据共享复杂,需要用IPC;数据是分开的,同步简单 | 因为共享进程数据,数据共享简单,但也是因为这个导致同步复杂 | 各有优势 |
内存、cpu | 占用内存多,切换负责,cpu利用率低 | 占用内存少,切换简单,cpu利用率高 | 线程占优 |
创建销毁、切换 | 创建销毁复杂,速度慢 | 创建销毁简单,速度很快 | 线程占优 |
编程、调试 | 编程简单,调试简单 | 编程复杂、调试复杂 | 进程占优 |
可靠性 | 进程间不会相互影响 | 一个线程挂掉将导致整个进程挂掉 | 进程占优 |
分布式 | 适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单 | 适应于多核分布式 | 进程占优 |
1.需要频繁发创建销毁的优先使用线程
常见Web服务器,来一个连接创建一个线程,断了就销毁线程,要是用进程,创建和销毁的代价都是难以承受的
2.需要进行大量计算的优先使用线程
所谓大量计算,就是要耗费很多cpu,切换频繁了,这种情况下线程是适合的;常见:图像处理,算法处理;
强相关的用线程处理,弱相关的用进程处理
如:消息收发,消息处理;
消息收发和消息处理属于若相关任务,分进程设计
消息处理里面可能又分消息解码、业务处理,关联性强,分线程设计;
可能要扩展到多机器分布用进程,多核分布用线程
都可满足的情况,用擅长的
worker_threads模块
利用cluster开启多进程
ab是apache自带的压力测试工具
ab -n1000 -c20 '192.168.31.25:8000/'
const cluster = require('cluster'); // 多进程 const http = require('http'); const numCpus = require('os').cpus().length; // 获取cpu的核数 if(cluster.isMaster){ // 是否是主线程 for(var i = 0; i < numCpus; i++){ cluster.fork() // 开启子线程 cluster.on('exit', function(worker, code ,signal){ // 监测哪个进程挂掉 console.log('worker'+worker.process.pid+'died') }) } } else { http.createServer((req,res) =>{ res.writeHead(200); res.end('hello world'); }).listen(8000) }
多进程的性能要明显好于单进程
ab是apache自带的压力测试工具,推荐使用mac
ab -n1000 -c20 '192.168.31.25:8000/'
n 请求数量
c 并发数量
vscode的.vscode下面配置 launch.json; 调试 修改program 工作目录
Process进程,child_process子进程,Cluster集群
process对象是Node的一个全局对象,提供当前Node进程的信息,它也可以在脚本的任意位置使用,不必通过require获取;
属性
process.argv属性,返回一个数组,包含了node进程时的命令行参数;
process.env返回包含用户环境信息的对象,可以在脚本中心对这个队形进行curd操作;
process.pid返回当前进程的进程号
process.platform 返回当前的操作系统
process.version 返回当前node的版本
方法
process.cwd() 返回node.js进程当前的工作目录
proces.chdir() 变更node.js进程的工作目录
process.nextTick() 将任务放到当前时间循环的尾部,添加到next tick队列,一旦当前时间轮询队列的任我全部完成,在next tick队列的所有callback会被依次调用;
process.exit() 退出当前进程时触发;很多时候是不需要的;
process.kill(pid[,signal]) 给指定的进程发信号,包括但不限于结束进程;
事件
beforeExit事件,在node清空了EventLoop之后,再没有任何待处理任务时触发,可以在这里再部署一些任务,使得node进程不退出,显示的终止程序时(process.exit()),不会触发;
exit事件,当前进程退出时触发,回调函数中只允许同步操作,因为执行完回调后,进程全部退出;
uncaughtException事件,兜底方案,当前进程抛出一个没有捕获的异步错误时触发,可以用它在进程结束前进行一些已分配资源的同步清理操作,尝试用它来恢复应用的正常运行的操作是不安全的;
warning事件;任何nodejs发出的警告都会触发此事件;
bbb() // 这里会直接报错,因为js是单线程的, // uncaughtException专门是捕捉异步代码错误,特别是http process.on('uncaughtException', (err) =>{ console.log(err) })
const http = require('http'); http.createServer((req, res) => { ccc() }).listen(8000, () => { console.log(`server is runing on 8000`) }) process.on('uncaghtException', (err) => { // 这里会捕获ccc的异步错误s console.log('发生错误',err) })
node中用于创建子进程的模块,cluster就是基于child_process模块封装的;
child_process.exec()
执行异步命令,运行结束后调用回调函数,或监听事件输出;
参数可以随便输入,安全性不高
方法2在监听到data事件以后, 可以一边读取一边接收结果,不用等子进程结束;如果子进程运行时间较长,或者持续运行,建议使用方法2;
const exec = require('child_process').exec; // 1. 通过回调的方式接收结果 // exec('ls', (err, stdout, stderr) => { // // 在node中,容错处理和业务代码一样重要; // // 因为js是单线程,一旦发生错误,后面代码就不会执行 // if (err) { // console.log('stderr', stderr); // } // console.log('err', err); // console.log('stdout', stdout); // }); // 由于标准输出和标准错误都是流对象(stream),可以监听data事件 // 2. 通过流的方式返回结果, // 可以一边读取一边接收结果,不用等所有文件读取完 var child = exec('lss'); child.stdout.on('data', data => { console.log(data); }); // 发生错误 child.stderr.on('data', err => { console.log('发生错误了', err); }); console.log(111)
child_progress.execSync() 同步方法
var execSync('child_progress'); var path = '../' var child = execSync(`ls ${path} \ rm rf`); // 这样会删除此文件夹的上一级目录的所有文件 console.log(child.toString());
execFile()
直接执行特定的程序shell,参数作为数组传入,不会被bash解释,因此具有较高的安全性;
会自动过滤一些敏感的字符串,如:'\ ;'
const { execFile } = require('child_progress') execFile('ls', ['-c'], (err, stdout, stderr) => { console.log('stdout', stdout) })
child_process.spawn()
spawn 创建一个子进程来执行特定的shell,用法和execFile 类似,但是没有回调函数,只能通过监听事件来获取运行结果,它属于异步执行,适用于子进程长时间运行的情况;
spawn 返回的结果是buffer,需要转成utf8;
const { spawn } = require('child_process'); let child = spawn('ls', ['-c']); child.stdout.on('data', data => { console.log('data', data.toString('utf8')); });
child_process.fork()
child_process.fork() 会创建一个子进程,执行node脚本,
child_process.fork('./child.js') 相当于 child_process.spawn('node', ['./child.js']);
与child_process.spawn()方法不同的是,child_process.fork()方法会在父进程和子进程之间建立一个通信管道pipe,用于进程之间的通信,也是IPC通信的基础;
main.js
const child_process = require('child_process'); const path = require('path'); var child = child_process.fork(path.resolve(__dirname, './child.js')); child.on('message', data => { console.log('父接收到子消息:', data); }); child.send('父亲send', data => { console.log('父亲说:为父给你发消息了'); });
child.js
process.on('message', data => { console.log('儿子接收到父亲消息:', data); }); process.send('儿子send', data => { console.log('儿子对父亲说:hello '); });
看完上述内容,你们对nodejs中怎么实现多进程有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注创新互联行业资讯频道,感谢大家的支持。