timeit测性能需控变量:用repeat取最小值、setup隔离依赖、禁用gc;extend非万能,大迭代器慎用;@lru_cache需规避不可哈希参数;async不加速cpu密集任务。

用 timeit 测函数性能,却忘了控制变量
很多人一上来就写 timeit.timeit('my_func()', number=100000),结果发现 A 比 B 快,上线后反而更慢——根本原因是没隔离解释器启动、GC 干扰、缓存预热等噪音。
实操建议:
- 用
timeit.repeat而不是单次timeit,取多次运行的最小值(排除 GC 突发暂停) - 把待测函数和依赖数据一起放进
setup参数,避免全局查找开销干扰测量 - 测试前手动调用
gc.disable(),尤其在对比小对象创建/销毁时,否则 GC 时间会混进结果里 - 如果函数内部有 I/O 或系统调用,
timeit测出来的只是“调度时间”,得换cProfile或perf
list.append 和 list.extend 混用导致隐式扩容
看到“批量加元素”就无脑用 extend,其实不总对:如果传入的是生成器或迭代器,extend 会先转成 list 再扩容,内存翻倍;而循环 append 虽慢但省内存。
常见错误现象:处理大文件行数据时,lines.extend(file) 让内存暴涨 2x,OSError: Cannot allocate memory 直接挂掉。
立即学习“Python免费学习笔记(深入)”;
实操建议:
- 确认输入是已知长度的
list或tuple才用extend;否则优先用itertools.chain+ 列表推导,或直接生成器消费 - 想提前预留空间?Python 列表不支持 reserve,但可以用
[None] * n初始化再赋值,适合长度确定的场景 -
append平均摊还 O(1),但连续调用 100 万次仍比一次extend慢 3–5 倍——得看你的瓶颈在 CPU 还是内存
盲目用 @lru_cache 反而拖慢程序
@lru_cache 不是银弹。参数含不可哈希类型(比如 dict、list)、函数本身极轻量(如纯算术)、或缓存命中率长期低于 10%,它只会增加哈希开销和内存占用。
WebShop网上商店系统专注中小企业、个人的网上购物电子商务解决方案,淘宝商城系统用户/个人首选开店的购物系统!综合5500多用户的意见或建议,从功能上,界面美观上,安全性,易用性上等对网店系统进行了深度的优化,功能更加强大,界面模板可直接后台选择。WebShop网上商店系统特点:1 对于中小企业、个体、个人、店主和淘宝易趣等卖家,可利用WebShop快速建立购物网。2 源代码开放,利用WebS
使用场景错配典型表现:json.loads 结果缓存后,解析速度变慢;或递归函数加了 @lru_cache 却因参数含 numpy.ndarray 直接抛 TypeError: unhashable type。
实操建议:
- 先用
functools.cache(Python 3.9+)替代@lru_cache(),它省去哈希计算,适合无参或参数全可哈希的函数 - 检查缓存大小:默认
maxsize=128,高频低重复场景下可能频繁淘汰,设为None或合理整数 - 参数含复杂对象?自己实现 key 生成逻辑,或改用
functools.singledispatch分路处理
用 asyncio 加速 CPU 密集任务
async/await 对纯计算毫无帮助。拿 asyncio.run(calculate_pi(1000000)) 替代同步版本,不仅不快,还会因事件循环调度多出 10%–20% 开销。
性能影响很实在:CPU 密集型任务切 asyncio 后,GIL 依然锁死,协程无法并行,反而增加上下文切换成本。
实操建议:
- CPU 密集 → 用
multiprocessing或concurrent.futures.ProcessPoolExecutor - I/O 密集 → 才轮到
asyncio,且确保所有 I/O 调用都是 async 版本(比如aiohttp而非requests) - 混合场景?用
loop.run_in_executor把 CPU 工作丢给线程池,但注意线程池不是万能解——Python 线程受 GIL 限制,只对释放 GIL 的操作(如 numpy 计算)有效
最容易被忽略的是:async 函数里混用同步阻塞调用(比如 time.sleep、sqlite3.connect),整个 event loop 就卡死了,连带其他协程一起停摆。










