JavaScript算法(1)实现⼀个带并发限制的异步调度器 Scheduler

82 阅读2分钟

实现⼀个带并发限制的异步调度器 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. 起始1、2两个任务开始执⾏;

  2. 500ms时,2任务执⾏完毕,输出2,任务3开始执⾏;

  3. 800ms时,3任务执⾏完毕,输出3,任务4开始执⾏;

  4. 1000ms时,1任务执⾏完毕,输出1,此时只剩下4任务在执⾏;

  5. 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) {
        if (this.count >= this.max) {
            await new Promise((resolve) => this.queue.push(resolve))
        }

        this.count++
        const res = await promiseCreator()
        this.count--
        if (this.queue.length) this.queue.shift()()
        return res
    }
}

const timeout = time => new Promise(resolve => {
    setTimeout(resolve, time)
})

const scheduler = new Scheduler(2)
const addTask = (time, order) => {
    scheduler.add(() => timeout(time)).then(res => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// output: 2 3 1 4