Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

限制并发请求 #195

Open
funnycoderstar opened this issue Apr 28, 2022 · 0 comments
Open

限制并发请求 #195

funnycoderstar opened this issue Apr 28, 2022 · 0 comments

Comments

@funnycoderstar
Copy link
Owner

题目一

JS 实现一个带并发限制的异步调度器 Scheduler,保证同时运行的任务最多有两个;
完善下面的 Scheduler 类,使得以下程序能正确输出

class Scheduler {
    add(promise) {
        // ...
    }
}
const timout = (time) =>
    new Promise((resolve) => {
        setTimeout(resolve, time);
    });
const scheduler = new Scheduler();
const addTask = (time, order) => {
    scheduler.add(() =>
        timout(time).then(() => {
            console.log(order);
        })
    );
};
addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');

// output: 2 3 1 4
// 一开始,1, 2两个任务进入队列
// 500ms时,2完成,输入2;任务3进队
// 800ms时,3完成,输出 3;任务4进队
// 1000ms时,1完成,输出1
// 1200ms时,4完成,输出4

代码实现

主要思路:

  1. 使用一个队列 queue 来存储当前执行的函数
  2. 使用一个标识 running 表示当前并发执行的数量
  3. 判断当前队列是否为空或者 当前执行的并发个数为 2,则直接 return
  4. 取出
class Scheduler {
    constructor() {
        this.queue = [];
        this.running = 0;
    }

    run() {
        if (this.queue.length === 0 || this.running === 2) {
            return;
        }
        const p = this.queue.shift();
        this.running++;
        p().then((result) => {
            this.running--;
            this.run();
            return result;
        });
    }
    add(promise) {
        this.queue.push(promise);
        this.run();
    }
}
const timout = (time) =>
    new Promise((resolve) => {
        setTimeout(resolve, time);
    });
const scheduler = new Scheduler();
const addTask = (time, order) => {
    scheduler.add(() =>
        timout(time).then(() => {
            console.log(order);
        })
    );
};
addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');

// output: 2 3 1 4
// 一开始,1, 2两个任务进入队列
// 500ms时,2完成,输入2;任务3进队
// 800ms时,3完成,输出 3;任务4进队
// 1000ms时,1完成,输出1
// 1200ms时,4完成,输出4

题目二

  1. 实现一个批量请求函数 multiRequest(urls, maxNum),要求最大并发数 maxNum,
  2. 每当有一个请求返回,就留下一个空位,可以增加新的请求。
  3. 所有请求完成后,结果按照 urls 里面的顺序依次打出。
/**
 * 限制并发请求。逻辑步骤分解
1. count,存储当前执行的数据,和 MaxNum 做对比
2. 判断并发个数:count 和 maxNum 做对比
3. 并发执行请求,
4. 返回结果
 * @param {*} urls 
 * @param {*} maxNum 
 */
// 返回对应的result; 包含成功和异常的处理情况
function multiRequest(urls, maxNum) {
    return new Promise((resolve, reject) => {
        let i = 0; // 当前执行的第i个函数,需要用它来存储结果的顺序
        let peddingCount = 0; // 记录正在执行的函数个数
        let successCount = 0; // 记录已经执行完成的函数个数,用来判断是否所有的函数都已返回正确的结果
        let result = []; // 存储最后的结果
        async function run(index) {
            // 如果所有函数都已经执行完成了,就
            if (successCount >= urls.length) {
                return resolve(result);
            }
            // 判断正在执行的个数如果大于 maxNum 或者 index 越界,就停止执行
            if (peddingCount >= maxNum || index >= urls.length) {
                return;
            }
            peddingCount++;
            try {
                result[index] = await testFetch(urls[index]);
                console.log('get result =>', urls[index], index);
            } catch (e) {
                result[index] = e;
            }
            peddingCount--;
            successCount++;
            // 此时i就是上一下执行i++后的结果,所以先执行 run(i), 再执行 i++
            run(i);
            i++;
        }
        // 并发执行 maxNum 个
        while (peddingCount < maxNum) {
            run(i);
            i++;
        }
    });
}
function testFetch(ms) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(ms);
            resolve(ms);
        }, ms * 1000);
    });
}

multiRequest([1, 4, 2, 3], 2).then((res) => {
    console.log('result', res);
});

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant