2

Here is an example

>>> from timeit import timeit
>>> print(timeit('[y for y in range(100)]', number=100000))
0.7025867114395824
>>> print(timeit('(y for y in range(100))', number=100000))
0.09295392291478244
>>> print(timeit('set([y for y in range(100)])', number=100000))
1.0864544935180334
>>> print(timeit('set((y for y in range(100)))', number=100000))
1.1277489876506621

It is very confusing. Generator takes less time to create(and that is understandable) but why converting generator to set is slower than converting list when it should(atleast to my knowledge) have been the opposite.

4

1 回答 1

3

首先,对生成器表达式的创建进行计时是没有意义的。创建生成器不会迭代内容,因此速度非常快。找出在一个元素上创建生成器表达式与超过 1000 万个元素之间的区别:

>>> print(timeit('(y for y in range(1))', number=100000))
0.060932624037377536
>>> print(timeit('(y for y in range(10000000))', number=100000))
0.06168231705669314

与列表对象相比,生成器需要更多的时间来迭代:

>>> from collections import deque
>>> def drain_iterable(it, _deque=deque):
...     deque(it, maxlen=0)
...
>>> def produce_generator():
...     return (y for y in range(100))
...
>>> print(timeit('drain_iterable(next(generators))',
...              'from __main__ import drain_iterable, produce_generator;'
...              'generators=iter([produce_generator() for _ in range(100000)])',
...              number=100000))
0.5204695729771629
>>> print(timeit('[y for y in range(100)]', number=100000))
0.3088444779859856

在这里,我通过尽可能快地丢弃所有元素来测试生成器表达式的迭代。

这是因为生成器本质上是一个函数,一直执行到它产生一个值,然后暂停,然后再次激活下一个值,然后再次暂停。请参阅“yield”关键字有什么作用?以获得良好的概述。涉及此过程的管理需要时间。相比之下,列表推导不必花费这些时间,它会进行所有循环,而无需为生成的每个值重新激活和取消激活函数。

生成器是内存效率高的,而不是执行效率高的。它们有时可以节省执行时间,但通常是因为您避免分配和释放更大的内存块。

于 2017-09-06T16:44:38.477 回答