spawn,exec,execFile和fork关系
exec
│
execFile fork
│ │
└─────spawn─────┘ 用户层面
│
-----------│------------------------
│
│ nodejs内部
│
spawn(位于lib/internal/child_process.js)
从上图可以看出,在用户层面其他的三个函数都调用了child_process.spwan
子进程的stdio(标准输入输出)
- options.stdio的值是字符串时,有以下几种取值
- pipe:相当于['pipe', 'pipe', 'pipe'],子进程的stdio和父进程的stdio通过管道进行连接
- ignore:相当于['ignore','ignore', 'ignore'],子进程的stdio绑定到
/dev/null
,丢弃数据的输入输出。 - inherit:继承父进程相关的stdio,等同于
[process.stdin,process.stdout,process.sterr]
或者[0,1,2]
,此时子进程的stdio都是绑定在同一个地方。
- 当options.stdio值是数组的时候,前三个元素分别代表stdin,stdout,stderr。如果数组的元素大于3,
则会在父子进程之间建立额外的通讯通道
,他们可能是下面的值.
- pipe 通过管道进行通讯,管道两端分别连接父子进程,父进程可以通过
subprocess.stdin,subprocess.stdout,subprocess.stderr
来引用管道的一端。子进程可以通过process.stdin, process.stdout, process.stderr
来引用另外一端 - ipc:额外的通讯通道,通过ipc channel通讯
- stream:通过nodejs 的stream 对象通讯,对象底层文件描述符代表一个文件。如:
socket,tty,本地文件
等 - null, undefined,对于前三个元素,他们会设置为pipe,剩下的元素会设置为ignore
例子
- pipe
绑定到父进程的process.stdio中
const child_process = require("child_process");
const script = (function(data) {
console.log(data);
}).toString();
const node = child_process.spawn("node", ["-e", `( ${script}("pipe,只能通过父进程将它输出") )`], {
stdio: 'pipe'
});
node.stdout.on('data', data => {
console.log(data.toString())
})
- inherit
const child_process = require("child_process");
const script = (function(data) {
console.log(data);
}).toString();
child_process.spawn("node", ["-e", `( ${script}("inherit,这一般个会写到控制台") )`], {
stdio: [process.stdin, process.stdout, process.stderr]
// 和 stdio: 'inherit'相似
});
- 绑定文件描述符(fd)
const child_process = require("child_process");
const fd = require("fs").openSync("./node.log", "w+");
const script = (function(data) {
console.log(data);
}).toString();
const node = child_process.spawn("node", ["-e", `( ${script}("整数fd,这一般个会写到某个文件") )`], {
//stdio绑定到文件描述符fd,它代表文件node.log,因此会输出到该文件
stdio: [process.stdin, fd, fd]
});
- 绑定stream
const child_process = require("child_process");
const fd = require("fs").openSync("./node.log", "w+");
const script = (function(data) {
console.log(data);
}).toString();
const writableStream = require("fs").createWriteStream(null, {
flags: "a",
fd,
});
child_process.spawn("node", ["-e", `( ${script}("stream,这一般个会写到某个文件") )`], {
//输出到流所代表的目的地,注意这个流必须要有文件描述符,否则会失败
//这个例子中它会输出到文件node.log
stdio: [process.stdin, writableStream, fd]
});
- ipc通道
// parent.js
const child_process = require("child_process");
const node = child_process.spawn("node",['./child.js'], {
shell:false,
stdio: ['inherit', 'inherit', 'inherit','ipc']
});
node.send({from: 'parent'});
// child.js
process.on('message', function(m){
console.log('message from parent: ' + JSON.stringify(m));
});
process.send({from: 'child'});
detached 和守护进程
生成子进程的时候如果传递了detached=true
,则使得子进程成为新的session
和group
的leader
const child_process = require("child_process");
const ping = child_process.spawn("ping", ["localhost"], {
detached:true,
stdio: 'ignore'
});
ping.unref();
需要成为守护进程,必须要做到以下几点
- 子进程必须和父进程分离,即
detached=true
- 默认情况下父进程会等待已分离的子进程,调用
subprocess.unref()
来取消等待 - 子进程的IO和父进程不能联系。使用
stdio: 'ignore'
网友评论