一道并发的面试题,控制并发数量
文章目录
- 题目要求
- 解析题目
- 总结发现
- 补全SuperTask代码,实现逻辑
- 完整代码和结果
题目要求
解析题目
我们先看看这道题目的规律,看到前两个,还是挺正常的,任务1 10s后输出,任务 2 5s后输出。
任务3 却是8s后输出,但明明传入的是3s,可结果是8s后输出,这里其实我们就该考虑到,这个8s那来的,结合前面两个,可以想到,5 + 3 正好8s,所以这个任务3是等任务2执行完后在执行的。
再往下看任务4 这里传入4s,却是12s后输出的,很明显就是 8 + 4 的结果,所以任务4是在任务2和任务3执行的,而任务5 却是15s后输出,那就是在任务1 后执行的。
总结发现
如下所示
其实可以联想到,这里有两条任务线在并发执行,任务1 由于10s后才输出,任务2 是5s后输出,所以任务3 会排在任务2后面执行,这就是为啥任务3 明明传入3s,但结果是8s后才输出了,依次类推,任务4接上,到任务5时,任务1执行完毕,此时任务2那条线,任务4在执行占用,所以任务5接在任务1后执行。
补全SuperTask代码,实现逻辑
class SuperTask {constructor(parallelNum = 2) {this.parallelNum = parallelNum // 最大并发数this.taskList = [] // 存储任务线this.runNum = 0 // 正在执行的任务数}add(task) {// 不管怎样,先把任务存在数组里面,由于外面是.then,所以这里是promise,为了执行任务的时候,执行结束要回调,所以把resolve,reject也保存起来return new Promise((resolve, reject) => {this.taskList.push({task,resolve,reject,})// 存进来的时候调下执行函数this._run()})}_run() {// 如果正在执行的数量 小于 最大并发数 并且 存储任务线大于0, 那么就执行存储任务中的任务while (this.runNum < this.parallelNum && this.taskList.length) {// 拿出来任务,并删除存储任务线的数据const { task, resolve, reject } = this.taskList.shift()// 因为外面的timeout方法返回的是一个promise,所以这里是异步需要.thentask().then(resolve, reject).finally(() => {// 执行完了,正在执行任务数要--,并且再次调用下执行函数this.runNum--this._run()})// 这里正在执行的任务数要++this.runNum++}}
}
完整代码和结果
class SuperTask {constructor(parallelNum = 2) {this.parallelNum = parallelNum // 最大并发数this.taskList = [] // 存储任务线this.runNum = 0 // 正在执行的任务数}add(task) {// 不管怎样,先把任务存在数组里面,由于外面是.then,所以这里是promise,为了执行任务的时候,执行结束要回调,所以把resolve,reject也保存起来return new Promise((resolve, reject) => {this.taskList.push({task,resolve,reject,})// 存进来的时候调下执行函数this._run()})}_run() {// 如果正在执行的数量 小于 最大并发数 并且 存储任务线大于0, 那么就执行存储任务中的任务while (this.runNum < this.parallelNum && this.taskList.length) {// 拿出来任务,并删除存储任务线的数据const { task, resolve, reject } = this.taskList.shift()// 因为外面的timeout方法返回的是一个promise,所以这里是异步需要.thentask().then(resolve, reject).finally(() => {// 执行完了,正在执行任务数要--,并且再次调用下执行函数this.runNum--this._run()})// 这里正在执行的任务数要++this.runNum++}}
}// 题目要求如下 依次执行addTask函数,输出结果如下 任务1 10s后输出,任务2 5s后输出,任务3 8s后输出,任务4 12s后输出,任务5 15s后输出
const superTask = new SuperTask()function timeout(time) {return new Promise((resolve) => {setTimeout(resolve, time)})
}function addTask(time, name) {superTask.add(() => timeout(time)).then(() => {console.log(`任务${name}完成`)})
}addTask(10000, 1) // 10s后输出
addTask(5000, 2) // 5s后输出
addTask(3000, 3) // 8s后输出
addTask(4000, 4) // 12s后输出
addTask(5000, 5) // 15s后输出// 任务1 (10s后输出) => 任务5 (15s后输出)
// 任务2 (5s后输出) => 任务3 (8s后输出) => 任务4 (12s后输出)