高开思维面试:给你一堆ip地址,最高并发数为100,如何最快地找到最快rtt的ip地址?

153 阅读2分钟

给你一堆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

三种解法:

  1. 第一种:amax * (n % 100 + 1)
  2. 第二种:amin * (n % 100 + 1)
  3. 第三种:(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();
            });
        }
    });
};

完整代码两个函数贴在一起即可运行。