繁体   English   中英

为什么这个列表理解比等效的生成器表达更快?

[英]Why this list comprehension is faster than equivalent generator expression?

我在Windows上使用Python 3.3.1 64位和此代码片段:

len ([None for n in range (1, 1000000) if n%3 == 1])

与此相比,执行时间为136毫秒:

sum (1 for n in range (1, 1000000) if n%3 == 1)

在146ms执行。 在这种情况下,生成器表达式不应该比列表理解更快或更快吗?

我引用了Guido van Rossum 从列表理解到生成器表达式

... Python 3中的列表推导和生成器表达式实际上比它们在Python 2中更快! (并且两者之间不再存在速度差异。)

编辑:

我用timeit测量了时间。 我知道它不是很准确,但我只关心这里的相对速度,当我用不同的迭代次数测试时,我的列表理解版本的时间总是缩短。

我相信这里的差异完全在于1000000的成本增加。 在Mac OS X上使用64位Python.org 3.3.0进行测试:

In [698]: %timeit len ([None for n in range (1, 1000000) if n%3 == 1])
10 loops, best of 3: 127 ms per loop
In [699]: %timeit sum (1 for n in range (1, 1000000) if n%3 == 1)
10 loops, best of 3: 138 ms per loop
In [700]: %timeit sum ([1 for n in range (1, 1000000) if n%3 == 1])
10 loops, best of 3: 139 ms per loop

所以,理解并不比genexp快; 它们都需要大约相同的时间。 但是在list上调用len是即时的,而将1M数字相加则会使总时间再增加7%。

它扔了几个不同的号码,这似乎托起除非列出的是非常小(在这种情况下, 似乎得到更快),或足够大的内存分配开始成为一个显著因子(它尚未,在333K)。

借用这个答案 ,有两件事需要考虑:

1. Python列表是可索引的,并且获取其长度仅需要O(1)次。 这意味着在列表上调用len()的速度不依赖于它的大小。 但是,如果在生成器上调用len() ,则会消耗它生成的所有项,因此时间复杂度为O(n)。

2.参见上面的链接答案。 列表推导是一个紧凑的C循环,而生成器必须存储对迭代器内部的引用,并为它生成的每个项调用next(iter) 这为生成器创建了另一层开销。 在较小的范围内,可以安全地忽略列表推导和生成器之间的性能差异,但是在更大的范围内,您必须考虑这一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM