You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js中运行并行进程并限制同时运行的进程数量?

控制Node.js子进程并发数的实现方案

这问题我之前做批量任务的时候也遇到过,核心就是要控制并发进程数,保持同时运行的进程不超过5个,而且只要有一个进程结束,就立刻启动下一个任务,直到所有200个文件都处理完。下面给你两种实用的实现方式:


方法一:原生Promise手动控制(无额外依赖)

这种方式不需要安装任何第三方包,用Node.js原生的Promise和递归逻辑就能实现并发控制:

const { exec } = require('child_process');
// 你的200个文件数组
const files = ['word.doc', 'foo.pdf', 'a.txt', /* ... 其他文件 */];
const maxConcurrent = 5; // 最大并发数
let currentTaskIndex = 0;
let runningProcesses = 0;

// 封装单个文件的执行逻辑,返回Promise
function executeWork(file) {
  return new Promise((resolve, reject) => {
    // 注意给文件名加双引号,避免带空格的文件名解析错误
    const process = exec(`Work.exe "${file}"`, (error, stdout, stderr) => {
      if (error) {
        console.error(`处理文件 ${file} 出错:`, error.message);
        reject(error);
        return;
      }
      console.log(`文件 ${file} 处理完成`);
      resolve(stdout);
    });

    // 监听进程退出事件,确保无论正常结束还是异常退出都能捕获
    process.on('exit', (exitCode) => {
      if (exitCode !== 0) {
        reject(new Error(`文件 ${file} 进程退出码: ${exitCode}`));
      }
    });
  });
}

// 启动下一个任务的递归函数
function startNextTask() {
  // 所有任务都已启动,直接返回
  if (currentTaskIndex >= files.length) return;

  const currentFile = files[currentTaskIndex];
  currentTaskIndex++;
  runningProcesses++;

  executeWork(currentFile)
    .finally(() => {
      // 无论任务成功失败,都减少运行计数并启动下一个任务
      runningProcesses--;
      startNextTask();
    });
}

// 初始化启动maxConcurrent个任务
for (let i = 0; i < maxConcurrent; i++) {
  startNextTask();
}

代码说明:

  • executeWork:把child_process.exec的回调风格API包装成Promise,方便用异步逻辑控制流程
  • startNextTask:负责启动单个任务,任务结束后(不管成功还是失败)都会递归调用自己,启动下一个任务
  • 初始化阶段先启动5个任务,之后就靠每个任务结束后的finally回调自动补充新任务,始终保持最多5个进程在运行

方法二:使用async库的队列(更简洁)

如果愿意引入第三方依赖,async库的queue方法专门为这种并发队列场景设计,代码会更简洁易读:

首先安装依赖:

npm install async

然后实现代码:

const { exec } = require('child_process');
const async = require('async');
const files = ['word.doc', 'foo.pdf', 'a.txt', /* ... 其他文件 */];

// 创建并发队列,设置最大并发数为5
const taskQueue = async.queue((file, taskCallback) => {
  // 执行单个文件的处理逻辑
  exec(`Work.exe "${file}"`, (error, stdout, stderr) => {
    if (error) {
      console.error(`处理文件 ${file} 出错:`, error.message);
      taskCallback(error);
      return;
    }
    console.log(`文件 ${file} 处理完成`);
    taskCallback(null, stdout);
  });
}, 5);

// 监听队列全部完成事件
taskQueue.drain(() => {
  console.log('所有文件都已处理完成!');
});

// 将所有文件加入队列
taskQueue.push(files);

代码说明:

  • async.queue:第一个参数是单个任务的处理函数,第二个参数是最大并发数
  • taskQueue.push:把所有任务加入队列后,队列会自动控制并发数,一个任务完成就立刻启动下一个
  • drain事件:当队列里所有任务都处理完成时触发,适合做后续的收尾工作

额外注意点:

  1. 文件名空格处理:一定要给文件名加上双引号("${file}"),避免文件名包含空格时命令解析出错
  2. 错误处理:两种方案都包含了错误捕获,你可以根据需求调整错误处理逻辑(比如某个任务失败是否终止所有任务)
  3. 结果收集:如果需要收集所有任务的处理结果,可以在Promise版本里用数组存储resolve的值,或者在async队列的push方法里添加回调来收集

内容的提问来源于stack exchange,提问作者raxinaga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:58:31