你的生成器实际上只循环一次。一旦创建pow2_gen
, g
存放发电机;第一次通过loop
,该发电机被消耗,并发出StopIteration
。其他时间通过loop
, next(g)
(or g.next()
在Python 2)只是继续抛出StopIteration
,所以,实际上g
代表一个空序列。
为了使比较更加公平,您需要在每次循环时重新创建生成器。
您处理此问题的方式的另一个困难是您正在调用append
构建列表,这可能是构建列表最慢的方法。更常见的是,列表是使用列表推导式构建的。
下面的代码让我们可以更仔细地区分时间。create_list
and create_gen
使用列表理解和生成器表达式分别创建列表和生成器。time_loop
就像你的loop
方法,同时time_apply
是一个版本loop
每次通过循环都会重新创建可迭代对象。
def create_list(n=1000):
return [2**i for i in range(n)]
def create_gen(n=1000):
return (2**i for i in range(n))
def time_loop(iterator, n=1000):
for t in range(n):
for v in iterator:
pass
def time_apply(create_fn, fn_arg, n=1000):
for t in range(n):
iterator = create_fn(fn_arg)
time_loop(iterator, 1)
print('time_loop(create_list): %.3f' % timeit("time_loop(create_list(1000))",
setup="from __main__ import *",
number=10))
print('time_loop(create_gen): %.3f' % timeit("time_loop(create_gen(1000))",
setup="from __main__ import *",
number=10))
print('time_apply(create_list): %.3f' % timeit("time_apply(create_list, 1000)",
setup="from __main__ import *",
number=10))
print('time_apply(create_gen): %.3f' % timeit("time_apply(create_gen, 1000)",
setup="from __main__ import *",
number=10))
我的盒子上的结果表明建立一个列表(time_apply(create_list)
)在时间上类似于(甚至可能比)构建发电机(time_apply(create_gen)
).
time_loop(create_list): 0.244
time_loop(create_gen): 0.028
time_apply(create_list): 21.190
time_apply(create_gen): 21.555
您可以看到您在问题中记录的相同效果,即time_loop(create_gen)
比以下快一个数量级time_loop(create_list)
。同样,这是因为创建的生成器仅被迭代一次,而不是对列表进行多次循环。
正如您假设的那样,构建一个列表一次并对其进行多次迭代(time_loop(create_list)
)比多次迭代生成器要快(time_apply(create_gen)
)在这个特定的场景中。
列表和生成器之间的权衡将很大程度上取决于您创建的迭代器有多大。对于 1000 个项目,我希望列表速度会相当快。对于 100,000 个项目,情况可能看起来有所不同。
print('create big list: %.3f' % timeit("l = create_list(100000)",
setup="from __main__ import *",
number=10))
print('create big gen: %.3f' % timeit("g = create_gen(100000)",
setup="from __main__ import *",
number=10))
我在这里得到:
create big list: 209.748
create big gen: 0.023
Python 构建大列表需要使用 700 到 800 MB 的内存;发电机几乎不使用任何东西。在 Python 中,内存分配和垃圾清理的计算成本很高,并且可以预见地会使您的代码变慢;生成器是避免占用机器 RAM 的一种非常简单的方法,并且可以对运行时间产生很大的影响。