【每日一题】|编程题——从接口日志统计每个接口的 P95 响应时间

难度:中级
题型:笔试(编程题)
题目描述:性能测试结束后拿到一份压测日志,请实现函数 p95_by_api:按接口分组,统计每个接口的 P95 响应时间(该接口所有请求耗时升序排列后,取第 ceil(0.95*n) 个,n 为请求数)。

代码框架:

def p95_by_api(logs):
    """
    logs 形如 [{"api": "/order", "cost": 0.8}, ...],cost 单位秒
    返回 {接口名: P95耗时},保留 2 位小数
    """
    # 请在此处补全
    pass


assert p95_by_api([
    {"api": "/a", "cost": 1}, {"api": "/a", "cost": 2}, {"api": "/a", "cost": 3},
    {"api": "/a", "cost": 4}, {"api": "/a", "cost": 100},
]) == {"/a": 100.0}

assert p95_by_api([
    {"api": "/a", "cost": 0.1}, {"api": "/b", "cost": 0.5},
]) == {"/a": 0.1, "/b": 0.5}

assert p95_by_api([]) == {}

:point_right:参考答案/答题要点:

参考题解:

import math
from collections import defaultdict

def p95_by_api(logs):
    group = defaultdict(list)
    for log in logs:
        group[log["api"]].append(log["cost"])
    result = {}
    for api, costs in group.items():
        costs.sort()
        idx = math.ceil(0.95 * len(costs)) - 1  # 1-based 转下标
        result[api] = round(costs[idx], 2)
    return result

采分点:①分组用 defaultdict;②P95 下标换算 ceil(0.95*n)-1(写 int(0.95*n) 会差一位);③round 保留精度;④空输入边界;⑤加分项:数据量极大时用"计数排序/分桶近似"(耗时先分桶统计频次再累加找 95% 分位),不必全量排序。