# 子进程:利用Node整合外部应用程序

# 执行外部应用程序

# 技巧56 执行外部应用程序

最基本的执行外部应用程序。demo

const cp = require('child_process');
// 调用echo命令
cp.execFile('echo',['hello','world'],(err,stdout,stderr)=>{
    if(err){
        console.error('err',err);
    }
    // echo命令的输出 stdout或者stderr
    console.log('stdout',stdout);
    console.log('stderr',stderr);
});

# 技巧57 流和外部应用程序

执行外部程序并得到相应的输出流,可以使用spawn.demo

const cp = require('child_process');
const child = cp.spawn('echo',['hello','world']);
// stream
child.on('error',console.error);
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);

在此基础上,我们可以模仿pipeline. demo

const cp = require('child_process');
const cat = cp.spawn('cat',['messy.txt'])
const sort = cp.spawn('sort');
const uniq = cp.spawn('uniq');

cat.stdout.pipe(sort.stdin);
sort.stdout.pipe(uniq.stdin);
uniq.stdout.pipe(process.stdout);

# 技巧58 在shell中执行命令

使用exec执行shell命令.demo

const cp = require('child_process');
cp.exec('cat messy.txt | sort | uniq',(err,stdout,stderr)=>{
    console.log(stdout)
})

# 技巧59 分离子进程

一般情况下,父进程终结,所有子进程都会被终结。子进程被认为是附加到父进程上的。但是spawn可以分离一个子进程,使得子进程和父进程拥有相同的级别,这样父进程终结,子进程会继续执行直到自己终结。

const child = cp.spawn('./longrun',[],{detached:true})

通过设置detached为true,子进程升级为自己的进程组头。

但是这样子进程中断前,父进程会一直活跃,这是因为子进程的I/O和父进程是相互连接的。要处理子进程的I/O与父进程的连接,可以配置stdio参数。

stdio 支持字符串和数组形式。默认值为 'pipe', 等价于['pipe','pipe','pipe'],三个参数分别对应子进程的stdin stdout stderr。

可以直接采用ignore参数忽略这个流,也可以把I/O指向其他地方。

const fs = require('fs');
const cp = require('child_process');

const outFd = fs.openSync('./longrun.our','a');
const errFd = fs.openSync('./longrun.err','a');

const child = cp.spawn('./longrun',[],{
    detached:true,
    // 不需要提供输入给子进程 子进程输出到文件 这样父子进程I/O切断
    stdio:['ignore',outFd,errFd]
});

还有一点小问题,父进程依然会有对子进程的引用,子进程不中断父进程也不会中断

// 移除子进程在父进程的引用
child.unref();

# 执行Node 程序

# 技巧60 执行Node程序

在UNIX平台下,在文件开始添加#!/usr/bin/env node,即可作为可执行程序。

# 技巧61 Forking Node 模块

Node本身是单线程的,计算任务直接影响进程的性能,可以使用fork的进程运行计算任务。

// 主进程
const cp = require('child_process');
const child = cp.fork('./myChild',{silent:true});
// 接受child的消息
child.on('message',(msg)=>{
    console.log(`get msg from child`,msg);
});
// 发送消息给child
child.send('data from main');
// 从fork的Node模块中断连接
child.disconnect();


// myChild
// 接受消息
process.on('message',(msg)=>{
    // 发送消息
    process.send(`${msg} received`)
});

# 技巧62 运行作业

进程池

# 同步运行

# 技巧63 同步子进程

希望同步执行一些命令,可以使用execFileSync spawnSync execSync