Richown头像
Python 性能实验怎么按输入规模分层:先限定一次测量能回答什么封面图

Python 性能实验怎么按输入规模分层:先限定一次测量能回答什么

把输入规模、原始时间、重复次数与环境信息一起记录

只测一次一千个整数的求和,再问“这个实现快不快”,范围太大。它至多描述这台机器在这个时刻、这个规模下的一次调用。把输入规模放大,解释器开销、循环次数和整数计算成本的占比都可能改变。

本文只问一个较小的问题:同一个平方和程序,在一千、一万、十万个整数上,本次耗时分别是多少?没有模型推理,没有跨语言对比,也没有生产负载。

封面的显式循环仅示意平方和计算目标;本次实际计时对象是下方的生成器实现,两者没有做性能对照。正文图的“单次调用时间”指轮总时间除以调用次数得到的平均估计,不是逐请求延迟。

固定计算内容,再选规模

程序计算 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,0000.0374860.0380140.0395000.0385140.044931
10,0000.4104720.3803050.4118890.4485000.591417
100,0004.6390284.2270554.0125424.2044035.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

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--