线程池
在B站上看的一道题,看了题意后,进行了尝试。(之前也做过相似的题,最近面试也被考过一道类似的题目,当时差点没做出来。幸好面试官当时要我做的是另一个意思的。所以这个题就直接顺手写下
class Scheduler {
_current = 0
_pendingTasks: (() => Promise<any>)[] = []
_runningTask: Promise<any> | null = null
run() {
// 如果有任务并且还有坑位
if (this._current < this.num && this._pendingTasks.length > 0) {
this._current++
this._pendingTasks[0]().then(() => {
this._current--;
// 启动下一个任务
this.run()
})
this._pendingTasks = this._pendingTasks.slice(1, this._pendingTasks.length)
}
// 等待某些任务执行完去启动。
}
addTask(task: () => Promise<any>) {
this._pendingTasks.push(task)
// 启动!
this.run()
}
constructor(private num: number) {}
}
const getTime = () => {
const date = new Date()
return date.valueOf() / 1000
}
const start = getTime()
const createPromise = (time: number, desc: string) => new Promise<void>((resolve, reject) => {
console.log(`${desc} is start running ${getTime() - start}`)
setTimeout(() => {
resolve()
console.log(`${desc} fulfilled ${getTime() - start}`)
}, time)
})
const scehduler = new Scheduler(2)
scehduler.addTask(() => createPromise(1000, "first"))
scehduler.addTask(() => createPromise(2000, "second"))
scehduler.addTask(() => createPromise(3000, "third"))
scehduler.addTask(() => createPromise(4000, "forth"))
可以看到相应的 输出符合预期
面试时
当时面试官让我做的是
easy mode
有一个数组 ,有一个 async 函数 返回参数 a+b 的值,然后不能使用 + ,求数组和。那么很简单了
const add = async (a: number, b: number) => Promise.resolve(a + b)
const sum = async (arr: number[]) => {
let res = 0
for (let i = 0; i < arr.length; i++) {
res = await add(res, arr[i])
}
return res
}
sum([1,2,3,4]).then(console.log)
(牛客网死活输出不了数据,我猜测是牛客网宏任务运行完了就认为任务结束了,但是这个输出是在微任务里)
a little harder
有一个数组,还是求和,需要并行计算,减少计算时间。
我一开始还以为是线程池,然后还想了一会儿,但是线程池每个任务都是独立的,这个还是有一定依赖关系,有时候还会有一些问题,比如如下代码,可能会有问题
res=res+await add(a,b)
// 应写为
const _temp=await add(a,b)
res=res+_temp
上述代码如果有多个并行任务,取值的时候和更新的时候就不同步,就会计算错误。 后来经过面试官解释,大概明白什么意思了,这个还没有涉及到线程池,就是单纯的分组求和
const sum = async (arr: number[]) => {
if (arr.length === 1) {
return arr[0]
}
const promises = []
const set = Math.floor(arr.length / 2)
for (let i = 0; i < set; i++) {
promises.push(add(arr[2 * i], arr[2 * i + 1]))
}
if (arr.length - 1 === set * 2) {
promises.push(Promise.resolve(arr[arr.length - 1]))
}
const res = await Promise.all(promises)
return sum(res)
}
大概就是两两分组,每一组都同时进行,如果是奇数也放到结果的数组里,每一次递归将数组长度减小一半,最后获得结果。