Python timeit 的常见误用总结

8次阅读

timeit.timeit() 的 setup 参数用于前置初始化,避免将 import 或变量赋值开销计入测试;应将依赖全放 setup,stmt 仅留待测语句;作用域隔离需注意,命令行用 -s 预定义;优先用 repeat 取最小值而非平均值;timeit 仅适合纯 cpu 计算场景。

Python timeit 的常见误用总结

timeit.timeit() 的 setup 参数为什么总被忽略

很多人直接把测试代码塞进 stmt,却忘了初始化变量或导入模块——结果测的不是函数执行时间,而是 import 或赋值开销。比如测 json.loads() 却没提前定义好字符串,每次调用都重新生成,setup 就是干这个的。

实操建议:

  • setup 里放所有前置依赖:导入、变量定义、对象构造
  • 避免在 stmt 里写 import jsons = '{"a": 1}',它们该进 setup
  • 如果用字符串形式调用,setupstmt 是独立作用域,不能共享变量名(除非用 globals

错误示例:

timeit.timeit('json.loads(s)', number=100000)

——sjson 都未定义,会报 NameError

用 timeit.repeat() 而不是多次调用 timeit.timeit()

单次 timeit.timeit() 结果波动大,尤其在有 GC、CPU 频率调节、后台进程干扰时。这不是精度问题,是测量方法本身不可靠。

立即学习Python免费学习笔记(深入)”;

实操建议:

  • 默认用 timeit.repeat(repeat=5, number=100000),取返回列表最小值(排除抖动峰值)
  • 别手动循环调用 timeit.timeit() 五次再求平均——平均值会掩盖异常延迟,最小值才反映真实下限
  • repeatnumber 更影响稳定性:增大 number 只是延长单次运行,但 repeat 是真正重启计时上下文

命令行 timeit 怎么传带参数的函数

命令行模式不支持闭包局部变量,想测 functools.partial 或带默认参数的函数,容易卡在语法或作用域上。

实操建议:

  • -s(setup)预定义函数和参数:
    python -m timeit -s "from functools import partial; from math import sqrt; f = partial(sqrt, 123)" "f()"
  • 避免在命令行 stmt 中写 Lambda 或内联表达式(如 "(lambda x: x**2)(5)"),编译开销混入结果
  • 如果函数需要模块级状态(如缓存),命令行模式很难模拟,优先改用脚本内调用

timeit 测的是纯 CPU 时间,不代表真实场景性能

timeit 默认关闭 GC、禁用线程切换、反复执行同一段代码——这跟 Web 请求、文件读写、数据库查询等 I/O 密集型场景完全脱节。

实操建议:

  • 测 I/O 操作(如 open()requests.get())基本没意义:网络延迟、磁盘缓存、连接复用都会让结果失真
  • 对含 print()Loggingtime.sleep() 的代码,timeit 测出的只是“触发开销”,不是实际耗时
  • 真正要对比算法性能?确保两者都纯计算、无副作用、输入规模一致;否则不如用 cProfile 看真实调用

最容易被忽略的一点:timeit 的 number 不是“执行次数”而是“语句重复执行次数”,它不展开函数内部逻辑——你看到快,可能只是因为函数体短,而不是算法优。

text=ZqhQzanResources