node.js中process进程的概念和child_process子进程模块的使用方法示例


Posted in Javascript onFebruary 11, 2020

本文实例讲述了node.js中process进程的概念和child_process子进程模块的使用方法。分享给大家供大家参考,具体如下:

进程,你可以把它理解成一个正在运行的程序。node.js中每个应用程序都是进程类的实例对象。

node.js中有一个 process 全局对象,通过它我们可以获取,运行该程序的用户,环境变量等信息。

一、process 对象

console.log('可执行文件绝对路径', process.execPath);
console.log('版本号', process.version);
console.log('依赖库的版本号', process.versions);
console.log('运行平台', process.platform);
console.log('标准输入流', process.stdin);
console.log('标准输出流', process.stdout);
console.log('标准错误流', process.stderr);
console.log('命令行参数数组', process.argv);
console.log('系统环境变量', process.env);
console.log('进程ID', process.pid);
console.log('标题', process.title);
console.log('处理器架构', process.arch);

通过 memoryUsage() 查看内存使用量:

console.log(process.memoryUsage());
  • rss 表示进程占用的内存,包括堆,栈,代码段。
  • heapTotal 表示堆占用的内存。
  • heapUsed 表示堆使用的部分。
  • external 表示外部使用的部分,C++对象占用的。

对象,字符串,闭包存放于堆内存,变量存放于栈内存,js源代码存放于代码段。

console.log(process.memoryUsage());
let buf = Buffer.alloc(1024 * 1024 * 1024);
console.log(process.memoryUsage());

当我们通过Buffer创建一个足够大的变量时,这时只能借助于外部内存,使用C++去完成。node.js能够使用的内存上限是1.7G。

使用 chdir() 修改程序当前的工作目录,通过 cwd() 获取当前工作目录。

console.log(process.cwd());
//修改程序当前的工作目录
process.chdir('../');
console.log(process.cwd());

通过 exit() 来结束进程

process.exit(0);

调用 exit() 结束进程时,会触发 'exit' 事件。

process.on('exit', function () {
  console.log('程序退出了');
});
process.exit(0);

通过 kill() 给指定进程发送信号

SIGINT 程序终止信号,当用户按下ctrl+c时发出,将通知进程终止。

SIGTERM 程序结束信号,通知程序正常退出,kill()方法默认就是这个信号。

process.kill(process.pid, 'SIGINT');

通过 uptime() 返回程序运行的时间

console.log(process.uptime());

通过 hrtime() 计算代码段运行时间,hrtime() 返回一个数组,第一个表示秒,第二个表示纳秒

let start = process.hrtime();
let sum = 0;
for (i = 0; i < 1000000000; i++) {
  sum += i;
}
let end = process.hrtime(start);
console.log('耗时 : ', end[0], '秒');

当程序抛出一个没有被捕获的异常时,触发 'uncaughtException' 事件。

process.on('uncaughtException', function (err) {
  console.log('捕获了一个未被处理的异常');
  console.log(err);
});
//调用一个未定义的函数
test();

进程接收到一个信号时,会触发信号事件,我们可以监听到该事件。

//让标准输入流处于流动模式,让程序无法退出
process.stdin.resume();
process.on('SIGINT', function () {
  console.log('程序退出');
  process.exit(0);
});
process.on('SIGTERM', function () {
  console.log('程序结束');
});

二、子进程模块child_process的使用

我们都知道node.js是单线程的,如果某一个操作需要消耗大量资源和时间,会导致程序整体性能下降。

我们可以创建子进程,让子进程去跑那些费时费力的操作,而主线程该干嘛干嘛。

子进程间可以共享内存,通过互相通信来完成数据的交换。

1、通过 spawn() 创建子进程

const {spawn} = require('child_process');
//参数一表示,要执行的命令
//参数二表示,运行该命令的参数
//参数三表示,创建子进程的配置
let cp1 = spawn('node', ['1.js'], {
  //cwd表示当前子进程的工作目录
  cwd: process.cwd(),
  //子进程的环境变量
  env: process.env,
  //子进程的标准输入,标准输出,错误,的配置
  //pipe表示,父进程与子进程间建立管道,父进程可以访问子进程对应的输入,输出,和错误
  //ipc表示,父进程与子进程间建立一个专门用来传递消息的IPC通道,子进程调用send()方法向子进程发送消息,并触发'message'事件
  //ignore表示,忽略子进程的标准输入,标准输出,错误。
  //inherit表示,子进程共享父进程的标准输入,标准输出,错误。
  //stream表示,父进程与子进程共享一个流,比如文件流或socket。
  //正整数表示,父进程打开的文件描述符,与子进程共享,比如文件的fd。类似stream流对象共享。
  //null或undefined表示,父进程与子进程间创建管道
  stdio: ['pipe', process.stdout, 'pipe'],
  //子进程是否独立于父进程运行
  detached: false
});

1.js的代码:

console.log('hello');

运行代码后,我们可以看到子进程的 'hello',出现在了父进程的标准输出上。因为 stdio 的配置,我们让子进程与父进程共享标准输出。

spawn() 会返回一个子进程对象,我们可以监听该对象的一些事件。

const {spawn} = require('child_process');
let cp1 = spawn('node', ['1.js'], {
  cwd: process.cwd(),
  env: process.env,
  stdio: ['pipe', process.stdout, 'pipe'],
  detached: false
});
//子进程所有输入/输出终止时,会触发子进程的 'close' 事件
cp1.on('close', function (code, signal) {
  //当父进程关闭子进程时,signal表示父进程发送给子进程的信号名称
  console.log('子进程关闭了', code, signal);
});
//子进程退出时,会触发 'exit' 事件
//注意,子进程退出,子进程的输入/输出有可能并未关闭。因为输入/输出有可能多个进程共享。
cp1.on('exit', function (code, signal) {
  console.log('子进程退出', code, signal);
});
//子进程出错时,触发
cp1.on('error', function (err) {
  console.log(err);
});

注意,stdio 设置成 pipe ,是把子进程的stdin,stdout,stderr导向了 spawn() 返回的子进程对象的stdin,stdout,stderr。

然后父进程就可以通过子进程对象访问stdin,stdout,stderr。

const {spawn} = require('child_process');
let cp1 = spawn('node', ['1.js'], {
  cwd: process.cwd(),
  env: process.env,
  stdio: ['pipe', 'pipe', 'pipe'],
  detached: false
});
//监听子进程标准输入,输出,错误的数据。
cp1.stdin.on('data', function (data) {
  console.log(data.toString());
});
cp1.stdout.on('data', function (data) {
  console.log(data.toString());
});
cp1.stderr.on('data', function (data) {
  console.log(data.toString());
});

1.js的代码:

//往子进程标准输出中写入数据
console.log('我是标准输出');
//往子进程错误中写入数据
console.error('我是一个错误');
//往子进程标准输入中写入数据
process.stdin.write('我是标准输入');

当我们设置 stdio 为 ipc 时,会创建一个父进程与子进程传递消息的IPC通道。

const {spawn} = require('child_process');
let cp1 = spawn('node', ['1.js'], {
  cwd: process.cwd(),
  env: process.env,
  //注意这里,子进程只能有一个IPC通道
  stdio: ['pipe', 'ipc', 'pipe'],
  detached: false
});
//注意这里要用子进程对象进行监听
//监听有没有消息
cp1.on('message', function (data) {
  console.log('子进程发送的 : ', data.toString());
});
cp1.send('你好,子进程');

1.js的代码:

process.on('message', function (data) {
  console.log('父进程发送的 : ', data.toString());
});
//向父进程发送消息
process.send('你好,父进程');

默认情况下,只有子进程全部退出了,父进程才能退出。我们希望父进程退出了,子进程仍然独立运行。可以通过设置 detached 为 true。

默认情况下,父进程会等待所有子程退出后,才退出。通过使用 unref() 让父进程无需等待子进程就可直接退出。

const {spawn} = require('child_process');
const fs = require('fs');
let fd = fs.openSync('./1.txt', 'w', 0o666);
let cp1 = spawn('node', ['1.js'], {
  cwd: process.cwd(),
  //注意这里,把不需要的设置为ignore,不然主进程仍然会阻塞等待子进程
  stdio: ['ignore', fd, 'ignore'],
  detached: true
});
cp1.on('error', function (err) {
  console.log(err);
});
//解绑子进程,让父进程不用等待子进程
cp1.unref();

1.js的代码:

let i = 0;
let timer = setInterval(function () {
  if (i > 20) {
    clearInterval(timer);
  }
  process.stdout.write('写入数据' + i + '\r\n');
  i++;
}, 1000);

2、通过 fork() 创建子进程

fork() 是 spawn() 的特殊情况,用于创建新的进程,默认建立一个IPC通信通道,允许父进程与子进程进行消息传递。

fork() 返回一个子进程对象,子进程输入/输出操作执行完毕后,父进程不退出,子进程不会自动退出,需调用 exit() 显式退出。

const {fork} = require('child_process');
//参数一表示,运行的模块
//参数二表示,参数列表
//参数三表示,创建子进程的配置
let cp1 = fork('2.js', ['1', '2', '3'], {
  //子进程的工作目录
  cwd: process.cwd(),
  //子进程的环境变量
  env: process.env,
  //运行模块的可执行文件
  execPath: process.execPath,
  //传递给可执行文件的参数列表
  execArgv: process.execArgv,
  //为false表示父进程与子进程共享标准(输入/输出),为true时不共享。
  silent: false
});
cp1.on('error', function (err) {
  console.log(err);
});

2.js的代码:

for (let i = 0; i < process.argv.length; i++) {
  process.stdout.write(process.argv[i] + '\r\n');
}

父进程与子进程间,通过 send() 和 'message'事件来传递消息。

const {fork} = require('child_process');
let cp1 = fork('2.js', [], {
  cwd: process.cwd(),
  env: process.env,
  silent: false
});
//接收消息
cp1.on('message', function (data) {
  console.log('父进程收到 : ', JSON.stringify(data));
  process.exit(0);
});
//发送消息
cp1.send({name: '你好子进程'});

2.js的代码:

process.on('message', function (data) {
  console.log('子进程收到 : ', JSON.stringify(data));
  process.send({name: '你好父进程'});
});

3、通过exec() 创建子进程

exec() 可以开启一个子进程运行命令,并缓存子进程的输出结果。

const {exec} = require('child_process');
//参数一表示,要运行的命令
//参数二表示,配置选项
//参数三表示,进程终止时的回调
exec('dir', {
  //子进程的工作目录
  cwd: process.cwd(),
  //子进程的环境变量
  env: process.env,
  //输出的编码
  encoding: 'utf8',
  //超时时间
  timeout: 60 * 1000,
  //缓存stdout,stderr最大的字节数
  maxBuffer: 1024 * 1024,
  //关闭子进程的信号
  killSignal: 'SIGTERM'
}, function (err, stdout, stderr) {
  console.log(stdout.toString());
});

4、通过 execFile() 创建子进程

使用 execFile() 开启一个运行可执行文件的子进程。

const {execFile} = require('child_process');
//参数一表示,可执行文件的名称或路径
//参数二表示,参数列表
//参数三表示,配置选项
//参数四表示,进程终止时的回调
let cp1 = execFile('node', ['3.js', '1', '2', '3'], {
  //子进程的工作目录
  cwd: process.cwd(),
  //子进程的环境变量
  env: process.env,
  //输出的编码
  encoding: 'utf8',
  //超时时间
  timeout: 60 * 1000,
  //缓存stdout,stderr最大的字节数
  maxBuffer: 1024 * 1024,
  //关闭子进程的信号
  killSignal: 'SIGTERM'
}, function (err, stdout, stderr) {
  if (err) {
    console.log(err);
    process.exit();
  }
  console.log('子进程的输出 : ', stdout.toString());
});
cp1.on('error', function (err) {
  console.log(err);
});

3.js的代码:

process.argv.forEach(function (value) {
  process.stdout.write(value + '\r\n');
});

fork(),exec(),execFile() 都是基于 spawn() 的封装。

希望本文所述对大家node.js程序设计有所帮助。

Javascript 相关文章推荐
javascript 读取图片文件的大小
Jun 25 Javascript
JavaScript 事件入门知识
Apr 13 Javascript
纯javascript实现的小游戏《Flappy Pig》实例
Jul 27 Javascript
jQuery3.0中的buildFragment私有函数详解
Aug 16 Javascript
Angular.js与node.js项目里用cookie校验账户登录详解
Feb 22 Javascript
vue.js模仿京东省市区三级联动的选择组件实例代码
Nov 22 Javascript
Vue.js表单标签中的单选按钮、复选按钮和下拉列表的取值问题
Nov 22 Javascript
详解使用VueJS开发项目中的兼容问题
Aug 02 Javascript
个人小程序接入支付解决方案
May 23 Javascript
Vue中全局变量的定义和使用
Jun 05 Javascript
微信小程序 (地址选择1)--选取搜索地点并显示效果
Dec 17 Javascript
vue.js watch经常失效的场景与解决方案
Jan 07 Vue.js
小程序如何定位所在城市及发起周边搜索
Feb 11 #Javascript
JS+DIV实现拖动效果
Feb 11 #Javascript
vue项目中使用particles实现粒子背景效果及遇到的坑(按钮没有点击响应)
Feb 11 #Javascript
原生js拖拽实现图形伸缩效果
Feb 10 #Javascript
js实现单元格拖拽效果
Feb 10 #Javascript
详解Vue template 如何支持多个根结点
Feb 10 #Javascript
JavaScript canvas动画实现时钟效果
Feb 10 #Javascript
You might like
php下删除字符串中HTML标签的函数
2008/08/27 PHP
PHP版本常用的排序算法汇总
2015/12/20 PHP
PHP使用PDO操作数据库的乱码问题解决方法
2016/04/08 PHP
php根据用户名和手机号查询是否存在手机号码
2017/02/16 PHP
PHP读取Excel类文件
2017/05/15 PHP
jQuery模拟黑客帝国矩阵效果实例
2015/06/28 Javascript
jQuery实现的AJAX简单弹出层效果代码
2015/11/26 Javascript
简单了解Backbone.js的Model模型以及View视图的源码
2016/02/14 Javascript
JavaScript高级程序设计(第三版)学习笔记6、7章
2016/03/11 Javascript
JS基于MSClass和setInterval实现ajax定时采集信息并滚动显示的方法
2016/04/18 Javascript
BootStrap的Datepicker控件使用心得分享
2016/05/25 Javascript
JS简单生成两个数字之间随机数的方法
2016/08/03 Javascript
详解Angularjs 如何自定义Img的ng-load 事件
2017/02/15 Javascript
使用Node.js实现base64和png文件相互转换的方法
2020/03/11 Javascript
详解vue中在父组件点击按钮触发子组件的事件
2020/11/13 Javascript
[52:29]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#3Secret VS OG第三局
2016/03/03 DOTA
[10:24]郎朗助力完美“圣”典,天籁交织奏响序曲
2016/12/18 DOTA
[42:11]TNC vs Pain 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
[01:01:52]完美世界DOTA2联赛PWL S2 GXR vs Magma 第二场 11.25
2020/11/26 DOTA
Python中关键字nonlocal和global的声明与解析
2017/03/12 Python
Django使用httpresponse返回用户头像实例代码
2018/01/26 Python
python 求一个列表中所有元素的乘积实例
2019/06/11 Python
python对Excel按条件进行内容补充(推荐)
2019/11/24 Python
Python configparser模块常用方法解析
2020/05/22 Python
python环境搭建和pycharm的安装配置及汉化详细教程(零基础小白版)
2020/08/19 Python
Canal官网:巴西女性时尚品牌
2019/10/16 全球购物
出国留学介绍信
2014/01/13 职场文书
卖车协议书
2014/04/21 职场文书
干部鉴定材料
2014/05/18 职场文书
教师个人年度总结
2015/02/11 职场文书
安全生产警示教育活动总结
2015/05/09 职场文书
基层组织建设年活动总结
2015/05/09 职场文书
贷款收入证明格式
2015/06/24 职场文书
2016年度继续教育学习心得体会
2016/01/19 职场文书
CSS 制作波浪效果的思路
2021/05/18 HTML / CSS
R9700摩机记
2022/04/05 无线电