限制并发请求
Opened this issue · 0 comments
funnycoderstar commented
题目一
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
代码实现
主要思路:
- 使用一个队列 queue 来存储当前执行的函数
- 使用一个标识 running 表示当前并发执行的数量
- 判断当前队列是否为空或者 当前执行的并发个数为 2,则直接 return
- 取出
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
题目二
- 实现一个批量请求函数 multiRequest(urls, maxNum),要求最大并发数 maxNum,
- 每当有一个请求返回,就留下一个空位,可以增加新的请求。
- 所有请求完成后,结果按照 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);
});