关于最近频繁遇到的一个面试题 手写并发异步调度
流程分析:
整个的完整执行流程:
- 起始1、2两个任务开始执行;
- 500ms时,2任务执行完毕,输出2,任务3开始执行;
- 800ms时,3任务执行完毕,输出3,任务4开始执行;
- 1000ms时,1任务执行完毕,输出1,此时只剩下4任务在执行;
- 1200ms时,4任务执行完毕,输出4;
当资源不足时将任务加入等待队列,当资源足够时,将等待队列中的任务取出执行
在调度器中一般会有一个等待队列queue,存放当资源不够时等待执行的任务
具有并发数据限制,假设通过max设置允许同时运行的任务,还需要count表示当前正在执行的任务数量
当需要执行一个任务A时,先判断count==max 如果相等说明任务A不能执行,应该被阻塞,阻塞的任务放进queue中,等待任务调度器管理
如果count<max说明正在执行的任务数没有达到最大容量,那么count++执行任务A,执行完毕后count--
此时如果queue中有值,说明之前有任务因为并发数量限制而被阻塞,现在count<max,任务调度器会将对头的任务弹出执行
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;
}
}
const timeout = time =>
new Promise(resolve => {
setTimeout(resolve, time);
});
const scheduler = new Scheduler(2);
const addTask = (time, order) => {
//add返回一个promise,参数也是一个promise
scheduler.add(() => timeout(time)).then(() => console.log(order));
};
addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// output: 2 3 1 4
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。