给你一堆ip地址,最高并发数为100,如何最快地找到最快rtt的ip地址?
这是一道高级开发工程师的面试题,思路不难,问题在于如何取到最优解,以及代码实现。
解法
假设我们有 n 个 IP 地址,将这 n 个 IP 地址分为 (n % 100 + 1) 组,每组 IP 有 100 个,使用 fetch 函数去 ping 这些 IP,就可以获得 IP 的rtt了
但问题是如何最快呢?
优化角度
1. 只 Ping 最短的 IP 地址
在 fetch 的过程中,可否只 ping 每组中rtt最短的 IP 地址作为最快的秒数
这和百米冲刺的道理相似,只需要观察到第一个人跑完即可,因为我们在乎的只是冠军。
2. 进一步优化
如果这个人打破了世界纪录,那他就是世界上最快的。
同理,针对 IP 地址: 我们可以用一个变量维护当前最快的值。如果某个地址的 RTT 超过了当前最短的 RTT 值,后续的 IP 遍历只需判断是否超过这个最短值即可。如果超过,就说明这一组的所有 IP 都不符合要求,可以直接转为下一组。
时间假设
假设 IP 地址的快慢随机均匀分布在每一组中:
- 最快时间是
amin - 最慢时间是
amax
三种解法:
- 第一种:
amax * (n % 100 + 1) - 第二种:
amin * (n % 100 + 1) - 第三种:
(amin / 2) * (n % 100 + 1)(为什么是 1/2 可以思考一下)
代码实现
核心函数
const findShortestRtt = async (ips) => {
// 定义结果
const result = {
ip: null,
rtt: Infinity
};
// 分组
const ipChunks = chunk(ips, 100);
// 遍历每组
for (const chunk of ipChunks) {
const curResult = await race(chunk);
if (result.rtt > curResult.rtt) {
result.ip = curResult.ip;
result.rtt = curResult.rtt;
}
}
// 返回结果
return result.ip;
};
辅助函数
chunk 函数
const chunk = (ips, conquantity) => {
const chunks = [];
for (let i = 0; i < ips.length; i += conquantity) {
chunks.push(ips.slice(i, i + conquantity));
}
return chunks;
};
race 函数
const race = async (chunk) => {
const time = Date.now();
return new Promise((resolve) => {
const controller = new AbortController();
const signal = controller.signal;
for (const ip of chunk) {
fetch(`http://${ip}/ping`, { signal }).then(() => {
resolve({ ip, rtt: Date.now() - time });
controller.abort();
});
}
});
};
完整代码两个函数贴在一起即可运行。