解密Node.js子进程:如何轻松处理CPU密集型任务

151 阅读2分钟

什么是 Child Process?

child_process 模块提供了一种在 Node.js 应用中创建和管理子进程的方式。子进程可以执行系统命令、运行其他 Node.js 脚本,甚至执行其他编程语言编写的程序。每个子进程都在独立的进程空间中运行,拥有自己的内存和资源,与主进程相互隔离。

为什么使用 Child Process?

  • 突破单线程限制: 将 CPU 密集型任务分配给子进程,避免阻塞主线程,提高应用的响应速度和稳定性。
  • 利用多核 CPU: 通过创建多个子进程,充分利用多核 CPU 的并行处理能力,提升应用的整体性能。
  • 执行系统命令: 方便地执行系统命令,例如文件操作、网络请求等。
  • 隔离错误: 子进程的崩溃不会影响主进程的运行,提高应用的容错性。
  • 调用其他语言编写的程序: 可以通过子进程调用其他编程语言编写的程序,例如 Python、Java 等,扩展 Node.js 的功能。

Child Process 的几种创建方式:

child_process 模块提供了多种创建子进程的方式,每种方式都有其适用的场景:

  • child_process.spawn() 最基础的创建子进程的方式,可以灵活地控制子进程的输入、输出和错误流。
  • child_process.exec() 执行一个 shell 命令,并将结果作为字符串返回。适用于执行简单的命令,例如获取系统信息。
  • child_process.execFile() 执行一个可执行文件,与 exec() 类似,但更安全,因为它不会执行 shell 命令。
  • child_process.fork() 创建一个新的 Node.js 进程,用于执行另一个 Node.js 脚本。适用于需要进行进程间通信的场景。

代码示例:

1. 使用 exec() 执行命令:

const { spawn, exec, execFile, fork } = require('child_process');
const cmd = process.platform === 'win32' ? 'dir /w' : 'ls -lh /usr';
exec(cmd, (error, stdout, stderr) => {
  if (error) {
    console.error(`exec error: ${error}`);
    return;
  }
  console.log(`exec stdout: ${stdout}`);
  console.error(`exec stderr: ${stderr}`);
});

2. 使用 execFile() 执行命令:

const { spawn, exec, execFile, fork } = require('child_process');
const execCommand = process.platform === 'win32' ? '.\\test.cmd' : '.\\test.sh';
const execArgs = process.platform === 'win32' ? [''] : [''];
execFile(execCommand, execArgs, (error, stdout, stderr) => {
  if (error) {
    console.error(`execFile error: ${error}`);
    return;
  }
  console.log(`execFile stdout: ${stdout}`);
  console.error(`execFile stderr: ${stderr}`);
});

3. 使用 fork() 创建 Node.js 子进程:

主进程 (main.js):

const { spawn, exec, execFile, fork } = require('child_process');
const child = fork(path.join(__dirname, 'child.js'));

child.on('message', (message) => {
  console.log(`父进程收到消息: ${message}`);
});

child.send({ hello: 'world' });

子进程 (child.js):

process.on('message', (msg) => {
  console.log('子进程收到消息:', msg);
  process.send('你好,父进程!');
});