Python交互式微基准测试方法及timeit使用疑问
在Python中实现类似Julia的交互式微基准测试(@btime/@benchmark功能)
我想在Python中交互式地对代码表达式(函数调用)做微基准测试,要求能自动根据计算成本/方差调整执行次数,类似Julia里的@btime/@benchmark功能。尝试用timeit.timeit时遇到两个疑问:
1. 如何解读timeit的测试结果?
测试代码及输出如下:
>>> a = 2.2 >>> timeit.repeat("round(a)", setup='from __main__ import a; gc.enable()', repeat=5,number=10) [4.631001502275467e-06, 1.3809185475111008e-06, 1.2170057743787766e-06, 1.1718366295099258e-06, 1.1730007827281952e-06] >>> timeit.timeit("round(a)", setup='from __main__ import a; gc.enable()', number=10) 5.741836503148079e-06 >>> timeit.timeit("round(a)", setup='from __main__ import a; gc.enable()') 0.11461802502162755 >>> timeit.Timer('round(a)', setup='from __main__ import a; gc.enable()').autorange() (5000000, 0.4272152939811349)
各输出的含义:
timeit.repeat返回的是5轮测试的总耗时,每轮执行number=10次round(a)。第一轮结果偏高是因为Python解释器首次执行有启动开销,后续几轮稳定后的值才代表真实执行耗时。timeit.timeit(number=10)的结果是10次执行的总耗时,结果偏高可能是单次测试的随机性,建议参考repeat的稳定值。- 不带
number参数时,timeit.timeit会自动选执行次数(默认让总耗时接近0.2秒),返回的是总耗时0.114秒,对应几十万次执行。 autorange()返回的元组是(执行次数, 总耗时),这里是执行500万次、总耗时0.427秒,单次执行耗时约为0.427/5000000 ≈ 8.54e-8秒,这是最准确的单次耗时参考。
你看到的"number从1改到10时结果稳定,之后数量级增长"是因为:number很小时,总耗时受系统调度、解释器启动开销影响大,结果波动大;number增大到一定程度,总耗时足够长能抵消噪声,结果更稳定,但总耗时自然随执行次数线性增长——你需要关注的是单次执行耗时(总耗时/number),而非总耗时本身。
2. 复用Timer对象修改stmt多次测试是否可行?
尝试的代码如下:
import timeit import gc bclass = timeit.Timer('round(1.1)','gc.enable()', globals=globals()) # 后续修改stmt测试不同函数 bclass.stmt = "small_3x2_nash.vertex_enumeration()" bclass.autorange() bclass.stmt = "small_3x2_nash.lemke_howson_enumeration()" bclass.autorange() bclass.stmt = "small_3x2_nash.support_enumeration()" bclass.autorange()
这种方式不可行:Timer对象初始化时会把stmt和setup编译成字节码,后续直接修改stmt属性不会触发重新编译,实际执行的还是最初的round(1.1),所以计时结果几乎一致。
正确做法:
- 每次测试新建一个Timer对象;
- 直接用
timeit.timeit传入不同的stmt参数; - 更推荐用IPython的
%timeit魔法命令,它会自动调整执行次数、统计均值和标准差,完全符合交互式测试需求,示例:
输出类似:%timeit round(a)85.4 ns ± 0.707 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
内容的提问来源于stack exchange,提问作者Antonello
相关产品推荐
相关产品推荐

