直接用 benchmark fixture 调用函数即可完成核心算法基准测试,但必须将 setup/teardown 移出待测路径、禁用干扰项、分组对比,否则测得的是噪声而非真实性能。

直接用 benchmark fixture 调用函数即可完成核心算法的基准测试,但必须控制 setup/teardown 开销、分组对比、禁用干扰项,否则测出来的是噪声不是性能。
为什么不能直接 benchmark(my_algorithm) 就完事
很多同学写完 def test_sort(benchmark): benchmark(sorted, data) 就跑,结果中位数跳变 ±30%,报告里 stddev 高得离谱。这不是算法不稳,是 data 构造逻辑混在了待测路径里——每次迭代都重新生成 list(range(10000)),这部分开销被算进了算法耗时。
- setup(如数据生成、对象初始化)必须移出
benchmark()调用外,用闭包或lambda显式包裹待测主体 - 避免在测试函数体里做任何非算法逻辑:不 print、不 assert 中间值、不调用 logging
- 若算法依赖外部状态(如缓存、全局 dict),需在
setup里预热并确保每次迭代起点一致
benchmark 的三种安全调用方式
传函数本身最干净,但要注意参数绑定时机;传 lambda 灵活但易捕获变量;benchmark.pedantic() 适合极端场景但默认不用。
-
推荐:直接传函数 + 显式参数 ——
result = benchmark(sorted, data),data必须在调用前已就绪 -
需要隔离 setup 时用 lambda ——
data = make_big_list(); result = benchmark(lambda: my_algo(data)),确保make_big_list()不在 lambda 内 - 极短函数( —— 用
benchmark.pedantic(my_func, rounds=10, iterations=1000),但会绕过自动校准,慎用
多算法横向对比必须设 group 和 name
不设 group,test_quick_sort_1000 和 test_merge_sort_1000 在报告里是孤立条目,无法看出“同输入下谁快”。不设 name,同一 group 内多个规模测试会堆成一团,看不出增长趋势。
立即学习“Python免费学习笔记(深入)”;
- 所有同类算法测试函数都加
benchmark.group = "sorting" - 用
benchmark.name标明关键差异:"quicksort / 1000 items"、"timsort / 1000 items" - 运行加
--benchmark-group-by=group --benchmark-sort=name,报告按组聚合、同组内按 name 排序并列显示
CI 中持续监控性能退化要防三个坑
本地跑一次没问题,推到 CI 就飘,常见于容器环境、资源限制、Python 版本差异。pytest-benchmark 自身不解决这些,但能帮你暴露问题。
-
--benchmark-min-time=0.01强制单轮至少跑 10ms,避免因 CI 机器慢导致迭代次数过少、统计失效 - 禁用 GC:
--benchmark-disable-gc,否则不同机器 GC 触发时机不同,max值剧烈抖动 - 固定计时器:
@pytest.mark.benchmark(timer=time.perf_counter),避免某些系统上time.time()被 NTP 调整干扰
真正难的不是跑出数字,而是让同一段代码在开发机、CI、预发环境里测出可比的 median 和低 stddev —— 这要求你把环境变量、依赖版本、甚至 CPU 频率都纳入控制范围,而 pytest-benchmark 只负责把「可控部分」测准。



















