各位程序猿/媛们,晚上好!我是你们的老朋友,代码界的段子手,今晚咱们来聊聊 Node.js 里那些“生孩子”的模块—— Child Processes。 别想歪了,我说的是 spawn
, exec
, 和 fork
这三个家伙。 他们可不是真的生孩子,而是让你在 Node.js 里开辟新的进程,执行一些系统命令或者启动其他的 Node.js 程序。
准备好了吗?咱们开始今天的“育儿”讲座!
Child Processes: 你的 Node.js “分身术”
想象一下,你的 Node.js 程序是个武林高手,但是有些招式(比如压缩大型文件,或者执行一些耗时的系统命令)它不太擅长。怎么办? 找个“分身”! 这些“分身”就是通过 Child Processes 模块创建的子进程。
为什么需要子进程?
- 并行处理: Node.js 是单线程的,意味着它一次只能做一件事。 如果你需要同时处理多个任务,子进程可以帮你实现并行。
- 执行系统命令: 你可以直接在 Node.js 程序中运行 shell 命令,比如
ls
,grep
,ping
等等。 - 隔离错误: 如果子进程崩溃了,不会影响到主进程。 就像你的“分身”被打死了,你本体还是活蹦乱跳的。
- 利用多核 CPU: 你可以启动多个子进程,让它们分别运行在不同的 CPU 核心上,充分利用你的硬件资源。
三兄弟:spawn
, exec
, fork
Child Processes 模块提供了三个主要的函数来创建子进程:spawn
, exec
, 和 fork
。 它们各有特点,就像三兄弟,性格不同,擅长的也不同。
| 函数 | 特点 |
| ——– | —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————- ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————0
spawn
: 灵活的“小泥鳅”
spawn
函数是最基础、最灵活的创建子进程的方式。 它以非阻塞的方式执行命令,并且通过流(streams)来处理输入和输出。 就像一只小泥鳅,滑不溜手,需要你亲自用网去捞。
基本用法:
const { spawn } = require('child_process');
const child = spawn('ls', ['-l', '/home']);
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
child.on('close', (code) => {
console.log(`子进程退出,退出码 ${code}`);
});
解释:
spawn('ls', ['-l', '/home'])
: 这行代码创建了一个新的子进程,执行ls -l /home
命令。ls
是要执行的命令,['-l', '/home']
是传递给命令的参数。child.stdout.on('data', (data) => { ... })
: 监听子进程的标准输出流。 当子进程有数据输出到标准输出时,这个回调函数就会被调用。child.stderr.on('data', (data) => { ... })
: 监听子进程的标准错误流。 如果子进程有错误信息输出到标准错误,这个回调函数会被调用。child.on('close', (code) => { ... })
: 监听子进程的close
事件。 当子进程退出时,这个回调函数会被调用,并传入子进程的退出码。
高级用法:
- 传递环境变量:
const { spawn } = require('child_process');
const env = { ...process.env, MY_CUSTOM_VAR: 'hello world' };
const child = spawn('node', ['-e', 'console.log(process.env.MY_CUSTOM_VAR)'], { env });
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`); // 输出: hello world
});
- 更改工作目录:
const { spawn } = require('child_process');
const child = spawn('ls', ['-l'], { cwd: '/tmp' });
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`); // 输出 /tmp 目录下的文件列表
});
- 处理二进制数据:
如果你需要处理二进制数据,比如图片或视频,你需要设置 encoding
选项为 null
。
const { spawn } = require('child_process');
const child = spawn('cat', ['image.png'], { encoding: null });
child.stdout.on('data', (data) => {
// data 是一个 Buffer 对象,包含图片的二进制数据
console.log(`received ${data.length} bytes of image data`);
});
exec
: 简单粗暴的大汉
exec
函数也是用来执行命令的,但是它会把整个命令的输出都缓冲到内存中,然后再一次性地返回给你。 就像一个大汉,一口气把所有东西都吃下去,然后再一股脑吐出来。
基本用法:
const { exec } = require('child_process');
exec('ls -l /home', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});
解释:
exec('ls -l /home', (error, stdout, stderr) => { ... })
: 这行代码执行ls -l /home
命令。exec
函数的回调函数会接收三个参数:error
(如果命令执行出错),stdout
(命令的标准输出),和stderr
(命令的标准错误)。
高级用法:
- 设置超时时间:
const { exec } = require('child_process');
exec('sleep 5 && echo "done"', { timeout: 2000 }, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`); // 如果 sleep 5 超过 2 秒,会输出超时错误
return;
}
console.log(`stdout: ${stdout}`);
});
- 设置最大缓冲区大小:
默认情况下,exec
函数的最大缓冲区大小是 200KB。 如果你的命令输出超过这个大小,exec
会报错。 你可以使用 maxBuffer
选项来增加缓冲区大小。
const { exec } = require('child_process');
exec('node -e "console.log('a'.repeat(1024*500))"', { maxBuffer: 1024 * 1000 }, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout.length: ${stdout.length}`); // 输出 stdout.length: 512000
});
fork
: Node.js 专属的“克隆术”
fork
函数是 spawn
函数的一个特殊版本,专门用来创建新的 Node.js 进程。 它会创建一个新的 Node.js 进程,并且在父进程和子进程之间建立一个 IPC (Inter-Process Communication) 通道。 就像你的 Node.js 程序学会了“克隆术”,克隆出来的分身可以和你直接对话。
基本用法:
// parent.js
const { fork } = require('child_process');
const child = fork('./child.js');
child.on('message', (message) => {
console.log('父进程收到消息:', message);
});
child.send({ hello: 'world' });
// child.js
process.on('message', (message) => {
console.log('子进程收到消息:', message);
process.send({ received: true });
});
解释:
const child = fork('./child.js')
: 这行代码创建了一个新的 Node.js 进程,执行child.js
文件。child.on('message', (message) => { ... })
: 监听子进程发送的消息。child.send({ hello: 'world' })
: 向子进程发送消息。process.on('message', (message) => { ... })
: 在子进程中监听父进程发送的消息。process.send({ received: true })
: 在子进程中向父进程发送消息。
高级用法:
- 共享内存: (需要
SharedArrayBuffer
和Atomics
,比较高级,谨慎使用)
// parent.js
const { fork } = require('child_process');
const buffer = new SharedArrayBuffer(1024);
const array = new Int32Array(buffer);
const child = fork('./child.js');
child.on('message', (message) => {
console.log('父进程收到消息:', message);
console.log('父进程中的数组值:', array[0]);
});
child.send({ buffer });
// child.js
process.on('message', (message) => {
const array = new Int32Array(message.buffer);
array[0] = 123;
console.log('子进程修改了数组值');
process.send({ done: true });
});
- 负载均衡: (配合
net
模块实现 TCP 服务器的负载均衡)
// master.js (主进程)
const net = require('net');
const { fork } = require('child_process');
const workers = [];
const numCPUs = require('os').cpus().length;
for (let i = 0; i < numCPUs; i++) {
workers.push(fork('./worker.js'));
console.log(`启动 worker ${i}`);
}
const server = net.createServer();
server.listen(8000, () => {
console.log('主进程监听 8000 端口');
});
server.on('connection', (socket) => {
const worker = workers[Math.floor(Math.random() * workers.length)];
worker.send('new connection', socket);
});
// worker.js (子进程)
const net = require('net');
const server = net.createServer((socket) => {
socket.end('handled by worker ' + process.pid + 'n');
});
process.on('message', (message, socket) => {
if (message === 'new connection') {
server.emit('connection', socket);
}
});
最佳实践和注意事项
- 选择合适的函数:
spawn
: 适合处理大量数据流,对内存占用较小。exec
: 适合执行简单的命令,并且需要获取完整的输出结果。fork
: 适合创建新的 Node.js 进程,并且需要在父进程和子进程之间进行通信。
- 错误处理: 务必处理子进程可能发生的错误,比如命令不存在、权限不足等等。
- 安全问题: 避免执行用户提供的命令,防止命令注入攻击。 如果必须执行用户提供的命令,一定要进行严格的验证和过滤。
- 资源限制: 限制子进程的 CPU 和内存使用,防止子进程占用过多资源导致系统崩溃。
- 进程管理: 使用进程管理工具(比如
pm2
,forever
)来管理你的 Node.js 进程,确保它们在崩溃后能够自动重启。 - 非阻塞 I/O: 记住 Node.js 的核心是异步非阻塞 I/O。 尽量使用
spawn
或fork
,避免使用exec
来执行耗时的命令,以免阻塞事件循环。
总结
Child Processes 模块是 Node.js 中一个非常强大的工具,它可以让你在 Node.js 程序中执行系统命令、启动其他程序、以及实现并行处理。 掌握 spawn
, exec
, 和 fork
这三个函数,就像学会了“分身术”,让你的 Node.js 程序更加强大和灵活。
记住,选择合适的函数,处理好错误,注意安全问题,你就能像一个熟练的“育儿师”一样,轻松驾驭这些子进程,让它们为你所用。
好了,今天的讲座就到这里。 希望大家有所收获,回去多多练习,早日成为 Child Processes 的大师!
有问题欢迎提问,没有问题的话… 散会!