You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何生成器表达式版foo比列表推导式版bar运行速度慢?

为啥生成器表达式的sum比列表推导式的sum慢?

这问题确实有点反直觉,我刚接触Python的时候也踩过类似的坑,来给你拆解一下背后的原因:

首先先明确你写的两个函数的核心差异:

  • foo用的是生成器表达式:sum(i*i for i in range(n)),它会逐个生成i*i的值,不会一次性把所有元素都存在内存里
  • bar用的是列表推导式:sum([i*i for i in range(n)]),会先把所有i*i的值生成一个完整的列表,再传给sum

核心原因:sum对序列类型的优化 + 缓存局部性

  1. sum的底层优化
    Python内置的sum函数对列表这类原生序列类型有专门的优化逻辑。当传入列表时,sum可以直接遍历列表的底层数组结构,减少了迭代过程中的额外开销;而生成器是基于迭代器协议工作的,每次获取下一个元素都要调用__next__()方法,还有yield的上下文切换成本,这些小开销累加起来,在n=50000这种规模下就会体现出来。

  2. CPU缓存的影响
    列表推导式生成的列表是一块连续的内存空间,CPU的缓存机制可以充分利用局部性原理——当访问一个元素时,相邻的元素也会被加载到缓存里,后续访问的速度会快很多;而生成器是按需生成元素,每个元素的内存地址不连续,缓存命中率低,自然会慢一些。

什么时候生成器会更快?

如果把n放大到非常大的量级(比如100万甚至更高),情况就会反转:

  • bar需要生成一个包含百万个元素的列表,会占用大量内存,当内存不足时还会触发系统的虚拟内存交换,速度会急剧下降
  • foo的生成器不需要一次性存储所有元素,内存占用极低,这时候迭代的额外开销就会被内存优势抵消,速度反而会比bar快

你的测试结果回顾

先把你的代码和测试结果贴出来更清晰:

def foo(n=50000): return sum(i*i for i in range(n)) # 直接调用sum(),未构造列表
def bar(n=50000): return sum([i*i for i in range(n)]) # 将构造好的列表传入sum()

测试输出:

In [2]: %%timeit
...: foo(50000)
...: 100 loops, best of 3: 4.22 ms per loop

In [3]: %%timeit
...: bar(50000)
...: 100 loops, best of 3: 3.45 ms per loop

简单来说就是:在数据规模不大的时候,列表的连续内存和sum的优化带来的速度提升,超过了生成器的内存优势;只有当数据规模大到内存成为瓶颈时,生成器才会展现出优势。

内容的提问来源于stack exchange,提问作者Gahan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:39:26