
只测一次一千个整数的求和,再问“这个实现快不快”,范围太大。它至多描述这台机器在这个时刻、这个规模下的一次调用。把输入规模放大,解释器开销、循环次数和整数计算成本的占比都可能改变。
本文只问一个较小的问题:同一个平方和程序,在一千、一万、十万个整数上,本次耗时分别是多少?没有模型推理,没有跨语言对比,也没有生产负载。
封面的显式循环仅示意平方和计算目标;本次实际计时对象是下方的生成器实现,两者没有做性能对照。正文图的“单次调用时间”指轮总时间除以调用次数得到的平均估计,不是逐请求延迟。
固定计算内容,再选规模
程序计算 0²+1²+...+(n−1)²。它有 n 次生成器迭代,不预先构造列表,返回一个整数。用闭式公式核对结果,但不把公式计算放进计时区间。
这三个规模呈十倍递增,方便观察工作量增加后的数量级变化,并不意味着覆盖了缓存或内存边界。Python 整数是任意精度对象,不能据此认定每次平方和加法都有严格恒定的机器成本。
下面脚本使用标准库即可运行。每个规模预热一次,每轮计时连续执行三次 work,将三次总耗时除以 3;每种规模测五轮,并以种子 42 打乱规模顺序。这个种子控制执行计划,不会固定计时结果。
import platform
import random
import timeit
from collections import defaultdict
def work(n):
return sum(i*i for i in range(n))
sizes = [1000, 10000, 100000]
for n in sizes:
assert work(n) == n*(n-1)*(2*n-1)//6
work(n)
schedule = sizes * 5
random.Random(42).shuffle(schedule)
raw = defaultdict(list)
for n in schedule:
elapsed = timeit.timeit(lambda: work(n), number=3)
raw[n].append(elapsed / 3)
print(platform.python_version(), platform.system(), platform.machine())
print(schedule)
for n in sizes:
print(n, raw[n])
正确性断言和预热都发生在计时前。传给 timeit 的 callable 本身也有调用开销,这部分包括在数值里;没有进行空函数扣减。

保留这次测量的原始序列
本次在 Python 3.9.6、Darwin、arm64 环境执行。没有锁定 CPU 频率、隔离后台负载或控制温度,因此下面是有限的本地观察。计时器为 timeit 默认的 perf_counter,单位为秒;为方便阅读,表中换算成毫秒并保留六位小数。
| n | 第1轮 | 第2轮 | 第3轮 | 第4轮 | 第5轮 |
|---|---|---|---|---|---|
| 1,000 | 0.037486 | 0.038014 | 0.039500 | 0.038514 | 0.044931 |
| 10,000 | 0.410472 | 0.380305 | 0.411889 | 0.448500 | 0.591417 |
| 100,000 | 4.639028 | 4.227055 | 4.012542 | 4.204403 | 5.793903 |
每个格子都是该轮三次调用的平均耗时,不是一次独立调用的原始延迟。同一行的轮次按该规模在计划中出现的先后编号,三行的“第1轮”并非同一时刻并行测得。
实际执行计划为:100000、10000、10000、1000、100000、1000、100000、100000、1000、1000、10000、100000、1000、10000、10000。三个规模的结果均在计时前通过公式断言。
这批数值中,规模增大伴随耗时上升;同规模内部也有波动。只能据此描述本次观察,不能用三行数据证明严格线性复杂度,更不能承诺换一台机器仍有相同比例。
为什么不只保留一个“最佳时间”
timeit 文档指出,其他程序可能干扰计时,最小值可作为这台机器执行该片段的一个速度参考。报告时仍应保留整组数据,让读者看见较慢轮次,不能把它们静默删除。
若目标是服务延迟,较慢请求可能正是需要解释的现象。这里三次调用合在一轮,并不保留每次延迟,所以不能计算请求级 p95 或 p99。把五个轮均值算一个分位数,也不会自动变成真实服务尾延迟。
timeit 默认在计时期间暂时关闭循环垃圾回收。当前计算没有构造长期保留的容器,但若换成对象图处理程序,垃圾回收可能是负载的一部分,就需要另设测量方案并记录开关。不能沿用这张表解释其他程序。
下一步增加什么,取决于问题是什么
若要比较两种实现,在每种规模下同时核对输出、交错执行两种实现,并保存各自记录。若要估计端到端文件处理时间,就把文件读取与输出纳入明确边界;当前表格完全没有测 I/O。
若要找到内存拐点,规模选择应围绕预期驻留量加密,而不是机械使用十倍档位。若要报告稳定差异,还需不同进程或时段的重复,以及足够长的计时轮次。本次每轮只执行三次,是一个很短的方法示例,尤其小规模结果更容易受固定开销影响。
输入分层的价值,是限制结论落在哪个工作量上。保留原始值和执行边界之后,才知道后续应补哪个规模,而不是把一个小数点更多的时间当成更可靠的证据。
参考:Python 3.9 timeit,2026-10-21 回查;文中测量在同日执行。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_40635035/article/details/169746792




