process模块来学习父子进程之间的通信(2)

其中file表示需要执行的文件。 child_process.execFile()和exec很相似,但是这个方法不会产生一个shell。指定的可执行文件会马上产生一个新的线程,因此其效率比child_process.exec高。

const execFile = require('child_process').execFile; const child = execFile('node', ['--version'], (error, stdout, stderr) => { if (error) { throw error; } console.log(stdout); });

因为不会产生shell,一些I/O redirection和file globbing这些行为不支持

child_process.fork(modulePath[, args][, options])

其中modulePath表示要在子线程中执行的模块。其中options中的参数silent如果设置为true,那么子进程的stdin, stdout, stderr将会被传递给父进程,如果设置为false那么就会从父进程继承。execArgv默认的值为process.execArgv,execPath表示用于创建子进程的可执行文件。这个fork方法是child_process.spawn的一种特殊用法,用于产生一个Node.js的子进程,和spawn一样返回一个ChildProcess对象。返回的ChildProcess会有一个内置的传输通道用于在子进程和父进程之间传输数据(用ChildProcess的send方法完成)。我们必须注意,产生的Node.js进程和父进程之间是独立的,除了他们之间的IPC传输通道以外。每一个进程有独立的内存,有自己独立的V8引擎。由于产生一个子进程需要其他额外的资源分配,因此产生大量的子进程不被提倡。默认情况下,child_process.fork会使用父进程的process.execPath来产生一个Node.js实例,options中的execPath允许指定一个新的路径。通过指定execPath产生的新的进程和父进程之间通过文件描述符(子进程的环境变量NODE_CHANNEL_FD)来通信。这个文件描述符上的input/output应该是一个JSON对象。和POSIX系统调用fork不一样的是,child_process.fork不会克隆当前的进程

最后,我们来看看子进程和父进程之间是如何通信的:

服务器端的代码:

var http = require('http'); var cp = require('child_process'); var server = http.createServer(function(req, res) { var child = cp.fork(__dirname + '/cal.js'); //每个请求都单独生成一个新的子进程 child.on('message', function(m) { res.end(m.result + '\n'); }); //为其指定message事件 var input = parseInt(req.url.substring(1)); //和postMessage很类似,不过这里是通过send方法而不是postMessage方法来完成的 child.send({input : input}); }); server.listen(8000);

子进程的代码:

function fib(n) { if (n < 2) { return 1; } else { return fib(n - 2) + fib(n - 1); } } //接受到send传递过来的参数 process.on('message', function(m) { //console.log(m); //打印{ input: 9 } process.send({result: fib(m.input)}); });

child_process.spawn(command[, args][, options])

其中options对象的stdio参数表示子进程的stdio配置;detached表示让子进程在父进程下独立运行,这个行为与平台有关;shell如果设置为true那么就会在shell中执行命令。这个方法通过指定的command来产生一个新的进程,如果第二个参数没有指定args那么默认就是一个空的数组,第三个参数默认是如下对象,这个参数也可以用于指定额外的参数:

{ cwd: undefined, //产生这个进程的工作目录,默认继承当前的工作目录 env: process.env//这个参数用于指定对于新的进程可见的环境变量,默认是process.env }

其中cwd用于指定子进程产生的工作目录,如果没有指定表示的就是当前工作目录。env用于指定新进程的环境变量,默认为process.env。下面的例子展示了使用ls -lh/usr来获取stdout,stderr以及exit code:

const spawn = require('child_process').spawn; const ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); ls.stderr.on('data', (data) => { console.log(`stderr: ${data}`); }); ls.on('close', (code) => { console.log(`child process exited with code $[code]`); });

下面是一个很详细的运行"ps ax|grep ssh"的例子:

const spawn = require('child_process').spawn; const ps = spawn('ps', ['ax']); const grep = spawn('grep', ['ssh']); ps.stdout.on('data', (data) => { grep.stdin.write(data); }); ps.stderr.on('data', (data) => { console.log(`ps stderr: ${data}`); }); ps.on('close', (code) => { if (code !== 0) { console.log(`ps process exited with code $[code]`); } grep.stdin.end(); }); grep.stdout.on('data', (data) => { console.log(`${data}`); }); grep.stderr.on('data', (data) => { console.log(`grep stderr: ${data}`); }); grep.on('close', (code) => { if (code !== 0) { console.log(`grep process exited with code $[code]`); } });

用下面的例子来检查错误的执行程序:

const spawn = require('child_process').spawn; const child = spawn('bad_command'); child.on('error', (err) => { console.log('Failed to start child process.'); });

options.detached:

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

转载注明出处:https://www.heiqu.com/wwyfpx.html