2022面试:任务并发数限制实现

128 阅读1分钟

假如有一个任务列表,每个任务项包含任务名称name和执行耗时time。形如

const tasks = [
    { name: 'a', time: 2000 },
    { name: 'b', time: 5000 },
    { name: 'c', time: 1000 },
    { name: 'd', time: 3000 },
    { name: 'e', time: 1000 },
    { name: 'f', time: 2000 },
    { name: 'g', time: 4000 }
]

要求实现一个函数进行任务调度,并能控制任务调度的并发数,最终能获取任务执行完成的顺序和总耗时

😊好巧不巧,之前在刷题的时候恰好思考过这个问题,面试的时候很顺利就写出来了。

递归实现

const request = (task) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(task)
        }, task.time)
    })
}

const handleTaskQueue = function (tasks = [], max = 3, callback = () => { }) {
    const tasksLen = tasks.length;
    const ret = [];
    let index = 0;
    const start = Date.now()
    const queue = []
    const run = function (task) {
        const promise = request(task)
        promise.then(res => {
            const retLen = ret.push(res.name)
            if (retLen < tasksLen && index + 1 < tasksLen) {
                queue.splice(queue.indexOf(promise), 1)
                run(tasks[++index])
            } else if (retLen === tasksLen) {
                'function' === typeof callback && callback({ ret, time: Date.now() - start })
            }
        })
        if (queue.push(promise) < max) {
            run(tasks[++index])
        }
    }
    run(tasks[0])
}

handleTaskQueue(tasks, 2, (ret) => {
    console.log(ret)
})

Promise.race实现

const request = (task) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(task)
        }, task.time)
    })
}

async function myAsyncPool(tasks = [], max = 3, callback = () => { }) {
    let queue = [];
    const ret = [];
    const start = Date.now()
    for (let i = 0; i < tasks.length; i++) {
        const task = request(tasks[i])
        task.then((data) => {
            // 当任务执行完毕, 将其从正在执行任务数组中移除
            ret.push(data.name)
            console.log(`当前并发数: ${queue.length}`)
            queue.splice(queue.indexOf(task), 1)
            if (ret.length === tasks.length) {
                'function' === typeof callback && callback({ ret, time: Date.now() - start })
            }
        })
        queue.push(task)
        if (queue.length === max) {
            await Promise.race(queue)
        }
    }
}
myAsyncPool(tasks, 3, (ret) => { console.log(ret) })

打印输出

image.png

在处理任务耗时上比较粗糙,没(qi)有(shi)进(bu)行(hui)任务耗时精确计算😂