跳至主要內容

并发任务控制

wzCoding大约 3 分钟综合知识并发任务控制

并发任务控制

在开发当中,我们可能会遇到页面上存在许多并发任务的情况,比如说:许多个获取服务器资源的远程请求,其他一些异步操作等,如果对这些并发任务处理不当,就可能会导致资源的占用。这时我们就需要对这些并发任务加以控制了。

控制并发

当需要控制多个异步任务的并发执行时,可以使用任务控制器。这个控制器可以限制同时进行的异步任务数量,保证队列中的任务按照顺序执行(先添加的任务先执行,后添加的任务后执行),并统一处理所有任务返回的 promise 对象。

一下是实现方式之一:

class TaskController {
    constructor(maxConcurrent) {
        this.maxConcurrent = maxConcurrent; // 最大并发数
        this.currentConcurrent = 0; // 当前并发数
        this.taskQueue = []; // 任务队列
    }

    add(task) {
        this.taskQueue.push(task); // 将任务函数加入队列
        this.run(); // 尝试执行任务
    }

    run() {
        while(this.currentConcurrent < this.maxConcurrent && this.taskQueue.length > 0) {
            const task = this.taskQueue.shift(); // 取出队列中的第一个任务函数
            this.currentConcurrent++; // 增加当前并发数
            task()
                .then((result) => {
                    console.log(result); // 如果成功,打印结果(或者做其他操作)
                })
                .catch((error) => {
                    console.error(error); // 如果失败,打印错误(或者做其他操作)
                })
                .finally(() => {
                    // 不管成功还是失败,都要减少当前并发数,并执行下一个任务(递归调用)
                    this.currentConcurrent--;
                    this.run();
                });
        }
    }
}

// 示例用法
const controller = new TaskController(2); // 创建一个异步任务控制器实例,最大并发数为2

// 模拟异步任务
const successTask = (id) => () => new Promise((resolve) => {
    setTimeout(() => resolve(id), 1000);
});

const failTask = (id) => () => new Promise((_, reject) => {
    setTimeout(() => reject(id*-1), 1000);
});

// 添加一些异步任务到控制器中
controller.add(successTask(1));
controller.add(failTask(2));
controller.add(successTask(3));
controller.add(failTask(4));
controller.add(successTask(5));

中断与恢复

上面的控制器有了基本的控制并发任务数量的功能,还缺少一个任务中断的功能,以下是实现任务中断功能的改进代码实现:

 class TaskController {
    constructor(maxConcurrent) {
        this.maxConcurrent = maxConcurrent; // 最大并发数
        this.currentConcurrent = 0; // 当前并发数
        this.taskQueue = []; // 任务队列
        this.isRunning = false; //是否正在执行并发任务
    }

    add(tasks) {
        if (typeof tasks === 'object' && tasks.length > 0) {
            this.taskQueue.push(...tasks);
        } else {
            this.taskQueue.push(tasks); // 将任务函数加入队列
        }
        console.log(this.taskQueue)
        this.run(); // 尝试执行任务
    }

    run() {
        if (this.isRunning) {
            return
        }
        this.isRunning = true

        while (this.currentConcurrent < this.maxConcurrent && this.taskQueue.length > 0) {
            const task = this.taskQueue.shift(); // 取出队列中的第一个任务函数
            this.currentConcurrent++; // 增加当前并发数

            task()
                .then((result) => {
                    console.log(`任务${result}开始`)
                    console.log(result); // 如果成功,打印结果(或者做其他操作)
                })
                .catch((error) => {
                    console.log(`任务${error}开始`)
                    console.error(error); // 如果失败,打印错误(或者做其他操作)
                })
                .finally(() => {
                    console.log(`任务结束`)
                    // 不管成功还是失败,都要减少当前并发数,并执行下一个任务(递归调用)
                    this.currentConcurrent--;
                    if (!this.isRunning) {
                        //如果外部手动中止任务,就停止执行
                        return
                    }
                    //当前任务执行完成后,恢复 isRunning 状态
                    this.pause();
                    //继续执行队列中的下一个任务
                    this.run();
                });
        }
    }
    pause() {
        this.isRunning = false //中断任务执行
    }
}

// 示例用法
const controller = new TaskController(2); // 创建一个异步任务控制器实例,最大并发数为2

// 模拟异步任务
const successTask = (id) => () => new Promise((resolve) => {
    setTimeout(() => resolve(id), 1000);
});

const failTask = (id) => () => new Promise((_, reject) => {
    setTimeout(() => reject(id*-1), 1000);
});

// 添加一些异步任务到控制器中
controller.add(successTask(1));
controller.pause()
controller.add(failTask(2));
controller.add(successTask(3));
controller.pause()
controller.add(failTask(4));
controller.add(successTask(5));