60. 异步调度器
题目描述:
实现一个带并发限制的异步调度器 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");
思路:
- 核心设计
任务队列 (
taskQueue
):存储待执行的任务,每个任务包含函数、resolve 和 reject。并发控制 (
maxConcurrent=2
):通过runningCount
计数器限制同时运行的任务数。自动调度 (
\_tryRun
):每次添加任务或任务完成时,检查队列并启动新任务。
- 执行流程
添加任务:将任务包装为
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