Node.js 单线程模型在多核 CPU 上存在资源浪费,通过 child_process 模块可创建子进程。本文详解 exec、spawn 和 fork 三种方法的实现代码、输出结果及核心区别,帮助开发者根据场景选择合适方案。
前言
Node.js 子进程模块概述
Node.js 采用单进程事件驱动模型处理并发任务。为了在多核 CPU 环境中充分利用计算资源,Node.js 提供了 cluster 和 child_process 模块,用于创建和管理多个子进程。
鉴于现代计算机普遍配备多处理器,Node.js 的单线程特性可能导致资源闲置。child_process 模块应运而生,它允许在主进程中派生子进程并执行特定任务,从而提升系统整体性能。
child_process 模块提供了 ChildProcess 类,作为父进程访问子进程的接口。Process 模块本身也是 ChildProcess 对象:在父进程中访问 process 时,它代表父级 ChildProcess;在子进程中访问时,则代表子级 ChildProcess。
理解一个对象通常需关注其事件、方法和属性,ChildProcess 也不例外。
每个子进程实例均包含三个流对象:child.stdin、child.stdout 和 child.stderr。这些流可能与父进程的 stdio 流共享,用于数据交互。
本文将重点介绍如何利用 child_process 模块中的 exec、spawn 和 fork 三个方法操作子进程。
首先,在项目中创建 node-childProcess 目录,并在其中建立 node-childPro.js 文件。
该文件仅包含一行核心代码:
console.log("进程 " + process.argv[2] + " 执行。" );
//换成下面的查看process.argv
//console.log("进程 " + process.argv + " 执行。" );
exec 方法实现与原理
exec() 方法
在 node-childProcess 目录下新建 node-childPro-exec.js 文件,代码如下:
const fs = require('fs');
const child_process = require('child_process');
for (var i = 0; i < 3; i++) {
//这里有空格请注意。分别代表node路径 node-childPro.js路径 i第几个进程。 node-childPro.js中的process.argv可以获取这些信息值
var childProcess = child_process.exec('node node-childPro.js '+i,
// 回调函数 子进程的输出以回调函数参数的形式返回
function (error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: ' + error.code);
console.log('Signal received: ' + error.signal);
}
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
});
childProcess.on('exit', function (code) {
console.log('子进程已退出,退出码 ' + code);
});
}
终端执行上述代码后的结果如下:
G:\node\node-childProcess> node node-childPro-exec.js
子进程已退出,退出码 0
stdout: 进程 0 执行。
stderr:
子进程已退出,退出码 0
stdout: 进程 1 执行。
stderr:
子进程已退出,退出码 0
stdout: 进程 2 执行。
stderr:
spawn 方法实现与原理
spawn() 方法
在 node-childProcess 目录下新建 node-childPro-spawn.js 文件,代码如下:
const fs = require('fs');
const child_process = require('child_process');
for(var i=0; i<3; i++) {
var childProcess = child_process.spawn('node', ['node-childPro-spawn.js', i]);
childProcess.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
childProcess.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
childProcess.on('close', function (code) {
console.log('子进程已退出,退出码 '+code);
});
}
终端执行上述代码后的结果如下:
G:\node\node-childProcess> node node-childPro-spawn.js
stdout: 进程 0 执行。
子进程已退出,退出码 0
stdout: 进程 1 执行。
stdout: 进程 2 执行。
子进程已退出,退出码 0
子进程已退出,退出码 0
fork 方法实现与原理
fork() 方法
在 node-childProcess 目录下新建 node-childPro-fork.js 文件,代码如下:
const fs = require('fs');
const child_process = require('child_process');
for(var i=0; i<3; i++) {
var childProcess = child_process.fork("node-childPro.js", [i]);
childProcess.on('close', function (code) {
console.log('子进程已退出,退出码 ' + code);
});
}
终端执行上述代码后的结果如下:
G:\node\node-childProcess> node node-childPro-fork.js
进程 0 执行。
进程 1 执行。
子进程已退出,退出码 0
进程 2 执行。
子进程已退出,退出码 0
子进程已退出,退出码 0
三种方法核心区别对比
关于 exec、spawn 和 fork 的区别:
1. exec 函数是对 spawn 的封装,增加了 Shell 命令解析功能,支持直接执行复杂的 Shell 命令。
2. exec 会缓存子进程的输出,并通过回调函数的参数形式将结果返回给主进程。
3. spawn 在子进程启动后,会持续将数据通过流的方式返回给主进程,适用于如系统监控等需要实时数据流的场景。
4. spawn 不支持回调函数,而是通过流(Stream)机制将数据传递给主进程,从而实现多进程间的数据交换。
5. fork 是 spawn 的特殊形式,专门用于派生 Node.js 进程。除了具备普通 ChildProcess 实例的所有方法外,返回的对象还内置了进程间通信通道。
示例代码下载地址:https://gitee.com/wangFengJ/node/tree/master/node-childProcess
总结
以上即为 Node.js 子进程创建的完整内容。希望本文对您的学习或工作有所帮助,如有疑问欢迎留言交流,感谢支持。