【发布时间】:2017-04-09 23:45:21
【问题描述】:
我预计在多个循环的情况下,列表迭代会比使用生成器快得多,而我的代码表明这是错误的。
我的理解是(通过操作我是指定义元素的任何表达式):
- 一个列表需要初始化 n 个操作
- 但是列表中的每个循环都只是从内存中抓取一个元素
- 因此,m 循环遍历列表只需要 n 个操作
- 生成器不需要初始化任何操作
- 但是,在生成器上循环运行操作会飞起来
- 因此,生成器上的一个循环需要 n 次操作
- 但是 m 在生成器上循环需要 n x m 操作
我使用以下代码检查了我的期望:
from timeit import timeit
def pow2_list(n):
"""Return a list with powers of 2"""
results = []
for i in range(n):
results.append(2**i)
return results
def pow2_gen(n):
"""Generator of powers of 2"""
for i in range(n):
yield 2**i
def loop(iterator, n=1000):
"""Loop n times over iterable object"""
for _ in range(n):
for _ in iterator:
pass
l = pow2_list(1000) # point to a list
g = pow2_gen(1000) # point to a generator
time_list = \
timeit("loop(l)", setup="from __main__ import loop, l", number=10)
time_gen = \
timeit("loop(g)", setup="from __main__ import loop, g", number=10)
print("Loops over list took: ", time_list)
print("Loops over generator took: ", time_gen)
结果让我吃惊...
Loops over list took: 0.20484769299946493
Loops over generator took: 0.0019217690005461918
不知何故,使用生成器似乎比列表快得多,即使循环超过 1000 次也是如此。在这种情况下,我们谈论的是两个数量级!为什么?
编辑:
感谢您的回答。现在我看到了我的错误。我错误地假设生成器从一个新循环开始,比如 range:
>>> x = range(10)
>>> sum(x)
45
>>> sum(x)
45
但这太天真了(范围不是生成器......)。
关于可能的重复评论:我的问题涉及生成器上的多个循环,其他线程中没有解释。
【问题讨论】:
-
您认为生成器更快的假设是不正确的。 Generators vs List Comprehension performance in Python 的可能重复项
-
速度差异相差两个数量级应该提醒您注意您的测试有问题。尝试
loop(pow_2_gen(1000))以获得准确的结果。 -
你的测试是否有缺陷。一个函数必须在内存中创建一个完整的列表,而另一个必须只返回一个迭代器。建议使用@Dunes 以获得更准确的结果。
-
我的意见是垃圾问题,因为从未在应用程序源代码中看到此代码。索引点在哪里,谁在没有任何索引的情况下使用这个数组,如何在线性模式下访问 RAM,如何管理 RAM 上的索引索引,为什么这让你感到惊讶?
标签: python performance list iteration generator