题目:实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有N个。完善下面代码中的 Scheduler 类,使得以下程序能正确输出:
class Scheduler {
add(promiseCreator) { ... }
// ...
}
const timeout = (time) => new Promise(resolve => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler(n)
const addTask = (time, order) => {
scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// 打印顺序是:2 3 1 4
我的分析:
1.Scheduler类的构造函数接收一个参数N,用来控制同时运行的任务;
2.add 接收一个函数参数,并返回一个promise;
3.需要使用一个队列来调度已添加但未运行的任务;
我的实现:
class Scheduler {
constructor(conut){
this.count = conut // 同时运行的最大任务数
this.runCount = 0 // 运行中的任务数
this.taskQueue = []
}
// 运行任务
static async runTask(task, resolve, reject){
await task().then(resolve, reject)
this.runCount --
if(this.taskQueue.length > 0){
let item = this.taskQueue.shift()
Scheduler.runTask.call(this, item.fun, item.resolve, item.reject)
}
}
add(promiseCreator) {
return new Promise((resolve, reject)=>{
this.runCount ++
if(this.runCount > this.count){
this.taskQueue.push({fun:promiseCreator, resolve, reject})
}else{
Scheduler.runTask.call(this, promiseCreator, resolve, reject)
}
})
}
}
运行结果:
其他实现:
class Scheduler {
constructor(max) {
this.max = max;
this.count = 0; // 用来记录当前正在执行的异步函数
this.queue = new Array(); // 表示等待队列
}
async add(promiseCreator) {
/*
此时count已经满了,不能执行本次add需要阻塞在这里,将resolve放入队列中等待唤醒,
等到count<max时,从队列中取出执行resolve,执行,await执行完毕,本次add继续
*/
if (this.count >= this.max) {
await new Promise((resolve, reject) => this.queue.push(resolve));
}
this.count++;
let res = await promiseCreator();
this.count--;
if (this.queue.length) {
// 依次唤醒add
// 若队列中有值,将其resolve弹出,并执行
// 以便阻塞的任务,可以正常执行
this.queue.shift()();
}
return res;
}
}