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 相关文章推荐
网页设计常用的一些技巧
Dec 22 Javascript
js加解密 脚本解密
Feb 22 Javascript
ExtJS 简介 让你知道extjs是什么
Dec 29 Javascript
javascript 在网页中的运用(asp.net)
Nov 23 Javascript
IE6弹出“已终止操作”的解决办法
Nov 27 Javascript
js实现文本框只允许输入数字并限制数字大小的方法
Aug 19 Javascript
jquery原理以及学习技巧介绍
Nov 11 Javascript
JavaScript中return用法示例
Nov 29 Javascript
vue.js的手脚架vue-cli项目搭建的步骤
Aug 30 Javascript
在Bootstrap开发框架中使用dataTable直接录入表格行数据的方法
Oct 25 Javascript
探索浏览器页面关闭window.close()的使用详解
Aug 21 Javascript
JS的深浅复制详细
Oct 16 Javascript
小程序如何定位所在城市及发起周边搜索
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安全上传图片的方法
2015/03/21 PHP
laravel学习教程之存取器
2016/07/30 PHP
微信公众平台开发(五) 天气预报功能开发
2016/12/03 PHP
php获取网站根目录物理路径的几种方法(推荐)
2017/03/04 PHP
Laravel利用gulp如何构建前端资源详解
2018/06/03 PHP
thinkphp5.1框架模板赋值与变量输出示例
2020/05/25 PHP
js 方法实现返回多个数据的代码
2009/04/30 Javascript
javascript window对象属性整理
2009/10/24 Javascript
关于flash遮盖div浮动层的解决方法
2010/07/17 Javascript
jQuery阻止事件冒泡具体实现
2013/10/11 Javascript
js/jquery解析json和数组格式的方法详解
2014/01/09 Javascript
javascript实现页面内关键词高亮显示代码
2014/04/03 Javascript
实例详解JavaScript获取链接参数的方法
2016/01/01 Javascript
js替换字符串中所有指定的字符(实现代码)
2016/08/17 Javascript
jQuery实现自动调用和触发某个事件的方法
2016/11/18 Javascript
Bootstrap实现各种进度条样式详解
2017/04/13 Javascript
React组件生命周期详解
2017/07/03 Javascript
jQuery实现键盘回车搜索功能
2017/07/25 jQuery
使vue实现jQuery调用的两种方法
2019/05/12 jQuery
详解Python里使用正则表达式的ASCII模式
2017/11/02 Python
python实现学生信息管理系统
2020/04/05 Python
解决pycharm 安装numpy失败的问题
2019/12/05 Python
python实现的批量分析xml标签中各个类别个数功能示例
2019/12/30 Python
Python基础之字典常见操作经典实例详解
2020/02/26 Python
Django使用rest_framework写出API
2020/05/21 Python
Python实现一个论文下载器的过程
2021/01/18 Python
牛津在线药房:Oxford Online Pharmacy
2020/11/16 全球购物
MAC彩妆澳洲官网:M·A·C AU
2021/01/17 全球购物
房产转让协议书
2014/04/11 职场文书
科级干部群众路线教育实践活动对照检查材料思想汇报
2014/09/20 职场文书
2014年电工工作总结
2014/11/20 职场文书
MySQL的join buffer原理
2021/04/29 MySQL
基于Redis实现分布式锁的方法(lua脚本版)
2021/05/12 Redis
Python答题卡识别并给出分数的实现代码
2021/06/22 Python
Python之matplotlib绘制饼图
2022/04/13 Python
如何让你的Nginx支持分布式追踪详解
2022/07/07 Servers