node多线程

最近弄一个在线打包的项目,需要用node去执行脚本打包。

关于node多线程:

我们都知道 Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的系统上创建多个子进程,从而提高性能。

每个子进程总是带有三个流对象:child.stdin, child.stdout 和child.stderr。他们可能会共享父进程的 stdio 流,或者也可以是独立的被导流的流对象。

Node 提供了 child_process 模块来创建子进程,方法有:

  • exec - child_process.exec 使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式返回。
  • spawn - child_process.spawn 使用指定的命令行参数创建新进程。
  • fork - child_process.fork 是 spawn()的特殊形式,用于在子进程中运行的模块,如 fork(‘./son.js’) 相当于 spawn(‘node’, [‘./son.js’]) 。与spawn方法不同的是,fork会在父进程与子进程之间,建立一个通信管道,用于进程之间的通信。

exec/execFile

exec(command, options, callback) 和 execFile(file, args, options, callback) 比较类似,会使用一个 Buffer 来存储进程执行后的标准输出结果,们可以一次性在 callback 里面获取到。不太适合输出数据量大的场景。

需要注意的是,exec 会首先创建一个新的 shell 进程出来,然后执行 command;execFile 则是直接将可执行的 file 创建为新进程执行。所以,execfile 会比 exec 高效一些。

spawn

spawn(command, args, options) 适合用在进程的输入、输出数据量比较大的情况(因为它支持以 stream 的使用方式),可以用于任何命令。

stdio

stdio 用来配置子进程和父进程之间的 IO 通道,可以传递一个数组或者字符串。比如,[‘pipe’, ‘pipe’, ‘pipe’],分别配置:标准输入、标准输出、标准错误。如果传递字符串,则三者将被配置成一样的值。我们简要介绍其中三个可以取的值:

  • pipe(默认):父子进程间建立 pipe 通道,可以通过 stream 的方式来操作 IO
  • inherit:子进程直接使用父进程的 IO
  • ignore:不建立 pipe 通道,不能 pipe、不能监听 data 事件、IO 全被忽略

fork

fork(modulePath, args, options) 实际上是 spawn 的一个“特例”,会创建一个新的 V8 实例,新创建的进程只能用来运行 Node 脚本,不能运行其他命令。并且会在父子进程间建立 IPC 通道,从而实现进程间通信。

我的项目

在项目里面,我需要创建shell脚本,并执行打包。所以我用的是execFile来执行sh命令,并添加路径。maxBuffer是来限制大小,默认的大小比较小,由于我这里打包文件比较大,所以需要手动配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const worker_process = process.execFile('sh',
['./bin/Build.sh'],
{maxBuffer: 1024 * 10000},
function(err, stdout, stderr){
if(err){
console.log(err);
}
console.log(stdout)
});
worker_process.on('close',function(code){
console.log('子进程已退出,退出码 ' + code)
console.log('打包完成')
})
worker_process.on('exit', function (){
console.log('Goodbye!');
});

在sh文件里面代码

1
2
3
4
#!/bin/sh
path1="/app/"
cd `dirname pwd`$path1 && pwd && npm run build