process模块详解(2)

const { spawn, execFile, fork } = require('child_process'); const child = spawn('echo $NODE_ENV', { shell: true, cwd: '/usr' }); child.stdout.pipe(process.stdout); NODE_ENV=randal node b.js // 输出结果 randal

如果指定env的话就会覆盖掉默认的环境变量,如下

const { spawn, execFile, fork } = require('child_process'); spawn('echo $NODE_TEST $NODE_ENV', { shell: true, stdio: 'inherit', cwd: '/usr', env: { NODE_TEST: 'randal-env' } }); NODE_ENV=randal node b.js // 输出结果 randal

detached用于将子进程与父进程断开连接

例如假设存在一个长时间运行的子进程

// timer.js while(true) { }

但是主进程并不需要长时间运行的话就可以用detached来断开二者之间的连接

const { spawn, execFile, fork } = require('child_process'); const child = spawn('node', ['timer.js'], { detached: true, stdio: 'ignore' }); child.unref();

当调用子进程的unref方法时,同时配置子进程的stdio为ignore时,父进程就可以独立退出了

execFile与exec不同,execFile通常用于执行文件,而且并不会创建子shell环境

fork方法是spawn方法的一个特例,fork用于执行js文件创建Node.js子进程。而且fork方式创建的子进程与父进程之间建立了IPC通信管道,因此子进程和父进程之间可以通过send的方式发送消息。

注意:fork方式创建的子进程与父进程是完全独立的,它拥有单独的内存,单独的V8实例,因此并不推荐创建很多的Node.js子进程

fork方式的父子进程之间的通信参照下面的例子

parent.js

const { fork } = require('child_process'); const forked = fork('child.js'); forked.on('message', (msg) => { console.log('Message from child', msg); }); forked.send({ hello: 'world' });

child.js

process.on('message', (msg) => { console.log('Message from parent:', msg); }); let counter = 0; setInterval(() => { process.send({ counter: counter++ }); }, 1000);

node parent.js // 输出结果 Message from parent: { hello: 'world' } Message from child { counter: 0 } Message from child { counter: 1 } Message from child { counter: 2 } Message from child { counter: 3 } Message from child { counter: 4 } Message from child { counter: 5 } Message from child { counter: 6 }

回到本文初的那个问题,我们就可以将密集计算的逻辑放到单独的js文件中,然后再通过fork的方式来计算,等计算完成时再通知主进程计算结果,这样避免主进程繁忙的情况了。

compute.js

const longComputation = () => { let sum = 0; for (let i = 0; i < 1e10; i++) { sum += i; }; return sum; }; process.on('message', (msg) => { const sum = longComputation(); process.send(sum); });

index.js

const http = require('http'); const { fork } = require('child_process'); const server = http.createServer(); server.on('request', (req, res) => { if (req.url === '/compute') { const compute = fork('compute.js'); compute.send('start'); compute.on('message', sum => { res.end(`Sum is ${sum}`); }); } else { res.end('Ok') } }); server.listen(3000);

监听进程事件

通过前述几种方式创建的子进程都实现了EventEmitter,因此可以针对进程进行事件监听

常用的事件包括几种:close、exit、error、message

close事件当子进程的stdio流关闭的时候才会触发,并不是子进程exit的时候close事件就一定会触发,因为多个子进程可以共用相同的stdio。

close与exit事件的回调函数有两个参数code和signal,code代码子进程最终的退出码,如果子进程是由于接收到signal信号终止的话,signal会记录子进程接受的signal值。

先看一个正常退出的例子

const { spawn, exec, execFile, fork } = require('child_process'); const child = exec('ls -l', { timeout: 300 }); child.on('exit', function(code, signal) { console.log(code); console.log(signal); }); // 输出结果 0 null

再看一个因为接收到signal而终止的例子,应用之前的timer文件,使用exec执行的时候并指定timeout

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/c07def3c1b600637c397fea9d9675781.html