60. 异步调度器

书诚小驿2025/02/23前端面经算法JavaScript

题目描述:

实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个

测试用例分析:

时间线: 0ms:任务 1 和 2 开始执行。 1000ms:任务 1 完成,输出 1,任务 3 启动。 2000ms:任务 2 完成,输出 2,任务 4 启动。 3000ms:任务 3 完成,输出 3。 3000ms:任务 4 完成,输出 4。 输出顺序:1 -> 3 -> 2 -> 4。

示例:

scheduler.addTask(1000, "1");
scheduler.addTask(2000, "2");
scheduler.addTask(1000, "3");
scheduler.addTask(1000, "4");

// 输出顺序:1 -> 3 -> 2 -> 4

模版:

class Scheduler {
  // 请输入你的代码
}

// 测试用例
const scheduler = new Scheduler();

// 添加任务(延迟时间,输出值)
scheduler.addTask(1000, "1");
scheduler.addTask(2000, "2");
scheduler.addTask(1000, "3");
scheduler.addTask(1000, "4");

思路:

  1. 核心设计
  • 任务队列 (taskQueue):存储待执行的任务,每个任务包含函数、resolve 和 reject。

  • 并发控制 (maxConcurrent=2):通过 runningCount 计数器限制同时运行的任务数。

  • 自动调度 (\_tryRun):每次添加任务或任务完成时,检查队列并启动新任务。

  1. 执行流程
  • 添加任务:将任务包装为 Promise 并推入队列。

  • 尝试执行:若当前运行任务数未达上限,从队列头部取出任务执行。

  • 递归触发:任务完成后,递归调用 \_tryRun 处理后续任务。

参考答案:

DETAILS
class Scheduler {
  constructor() {
    this.maxConcurrent = 2; // 最大并发数
    this.runningCount = 0; // 当前运行中的任务数
    this.taskQueue = []; // 待执行的任务队列
  }

  // 添加任务到调度器
  addTask(delay, value) {
    // 创建任务函数(返回 Promise)
    const task = () =>
      new Promise((resolve) => {
        setTimeout(() => {
          console.log(value); // 延迟结束后输出值
          resolve();
        }, delay);
      });

    // 将任务封装为 Promise 并加入队列
    return new Promise((resolve, reject) => {
      this.taskQueue.push({ task, resolve, reject });
      this._tryRun(); // 尝试启动任务
    });
  }

  // 尝试执行任务(内部方法)
  _tryRun() {
    while (
      this.runningCount < this.maxConcurrent &&
      this.taskQueue.length > 0
    ) {
      const { task, resolve, reject } = this.taskQueue.shift();
      this.runningCount++; // 增加运行计数
      task()
        .then(resolve)
        .catch(reject)
        .finally(() => {
          this.runningCount--; // 任务完成,减少计数
          this._tryRun(); // 递归触发下一个任务
        });
    }
  }
}

// 测试用例
const scheduler = new Scheduler();

// 添加任务(延迟时间,输出值)
scheduler.addTask(1000, "1");
scheduler.addTask(2000, "2");
scheduler.addTask(1000, "3");
scheduler.addTask(1000, "4");

// 输出顺序:1 -> 3 -> 2 -> 4
最后更新时间' 2025/3/9 18:24:05