【问题标题】:Why converting list to set is faster than converting generator to set?为什么将列表转换为集合比将生成器转换为集合更快?
【发布时间】:2018-02-15 05:49:09
【问题描述】:

这是一个例子

>>> 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

这很混乱。生成器需要更少的时间来创建(这是可以理解的),但是为什么将生成器转换为集合比在应该(至少据我所知)转换列表时要慢。

【问题讨论】:

  • (y for y in range(100)) 除了创建一个生成器对象之外什么也不做。没有进行任何迭代,因此与发生的其他事情相比,这确实是一个毫无价值的测试。
  • 生成器的优势在于内存消耗和提前终止的可能性;迭代整个生成器不会比迭代整个相应的列表理解更快。

标签: python performance python-3.x list-comprehension generator-expression


【解决方案1】:

首先,对生成器表达式的创建进行计时是没有意义的。创建生成器不会迭代内容,因此非常快。找出在一个元素上创建生成器表达式与超过 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

在这里,我仅通过 discarding all elements as fast as possible 测试了生成器表达式的迭代。

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

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

【讨论】:

  • 好的,所以你的意思是因为生成器比列表需要更多的时间来迭代;因此,将生成器转换为集合比将列表转换为相同要慢。感谢您的澄清。我不知道(或者我猜错了)生成器比列表慢。
  • @IsaacVassell:完全正确; set() 所做的只是遍历输入以添加结果元素,因此我关注它们的速度差异。
猜你喜欢
  • 2013-12-16
  • 2021-08-15
  • 2011-01-29
  • 1970-01-01
  • 1970-01-01
  • 2017-02-06
  • 2014-10-07
  • 2016-07-14
  • 2011-08-02
相关资源
最近更新 更多