spawn
创建子进程
// [0,1,2]相当于[process.stdin, process.stdout, process.stderr] const parent = spawn("node", ["child.js"], { cwd: path.resolve(__dirname, './child'), stdio: [0, 1, 2, "ipc"] })
进程通信方式 ipc/pipe
pipe流的方式
stdio:["pipe","pipe","pipe"]
// child.js process.stdout.write("子进程以流的方式输出"+fib(40)) process.stdout.on("data", (data) => { console.log("子进程收到父进程的数据"+ data.toString()); })
// parent.js // 收到子进程消息 parent.stdout.on("data", (data) => { console.log("父进程监听子进程的输出"+ data.toString()); }) // 给子进程发送消息 parent.stdout.write("父进程发送数据");
ipc通信
stdio:[0,1,2,"ipc"]
// child.js process.on("message",(data) => { console.log(data) }) process.send(obj)
// parent.js parent.on("message",(data) => { console.log(data) }) parent.send(obj)
ipc通信和pipe通信的区别
fork
创建子进程
fork默认调用的是node执行的命令,默认采用ipc的通信方法
const parent = spawn("child.js", { cwd: path.resolve(__dirname, './child'), })
当我们关闭父进程的时候,父进程创建的子进程也会随着关闭,那我们怎么创建一个独立的子进程呢
const parent = spawn("node", ["child.js"], { cwd: path.resolve(__dirname, './child'), stdio: ignore, detached:true, }) parent.unref()// 独立子进程
execFile
execFile支持多种启动方式
execFile可以设置timeout超时时间,一旦创建的进程运行超过设定的时间将会被杀死
我们可以看到execFile中有一个maxBuffer,因为stdout会先做一个汇总,再传到这个回调函数里面,可能会存在内存溢出,所以会限制一个maxBuffer
execFile("tec360", ['-datafile', url], (err, stdout, stderr) => { if (err) { // console.log('res on err',err) reject({msg:err,code:PROCESS_CODE.ERROR}) } else if (stderr) { // console.log('std err', stderr) reject({msg:stderr,code:PROCESS_CODE.ERROR}) } })
输出ls -ll命令结果
const parent = execFile("ls",["-ll"],{ cwd:path.resolve(__diname,"./") },(err,stdout,stderr) => { console.log(stdout) })
exec
用的比较少,但是可以打印命令行中的环境变量
可以设置timeout超时时间,一旦创建的进程运行超过设定的时间将会被杀死
const parent = exec("echo $PATH",{ cwd:path.resolve(__dirname,"./") })
集群cluster
父进程传递给子进程服务的方式,共同监听同一个端口
// 主进程 const http = require("http") const { fork } = require('child_process') const path = require('path'); const cpus = require("os").cpus() const server = http.createServer((req,res)=>{ res.end("master"+"\n"); }).listen(3000) for(let i = 0; i < cpus.length - 1; i++) { const cp = fork("server.js",{ cwd:path.resolve(__dirname,'.') }); cp.send("server",server); }
// server.js const http = require("http") // 如果子进程直接监听3000端口,会报错,因为父进程已经占用了3000端口 // const server = http.createServer((req,res) => { // res.end(process.id + "\n"); // }).listen(3000); process.on('message',(msg,server) => { http.createServer((req,res) => { res.end('child process' + "\n" + process.pid, + "\n"); }).listen(server) })
Cluster事件
const cluster = require('cluster') const http = require("http") const { resolve } = require("path") const cpus = require("os").cpus() // 第一种,判断是主进程还是工作进程的方式 // if(cluster.isMaster){ // cpus.forEach(() =>{ // cluster.fork(); // }) // }else { // http.createServer((req,res) => { // res.end("child procecss" + '\n'+process.pid+"\n") // }).listen(3000) // } // 第二种使用cluster.setupMaster()这个Api,在node16中应换成setupPrimary cluster.setupMaster({ exec:resolve(__dirname,"./server.js"), }) for(let i = 0; i < cpus.length; i++) { cluster.fork() } // 守护进程 cluster.on("exit",(worker,code,signal) => { console.log('worker died'); cluster.fork(); })