为什么元组在评估生成器时比列表慢?

时间:2015-01-20 12:44:20

标签: python performance list tuples python-internals

python -m timeit "tuple(xrange(600000))"
  

100个循环,最佳3:每循环11.5毫秒

python -m timeit "list(xrange(600000))"
  

100个循环,最佳3:每循环10.1毫秒


将它们与dis模块进行比较:

>>> from dis import dis
>>> dis(lambda: tuple(xrange(600000)))
      0 LOAD_GLOBAL              0 (tuple)
      3 LOAD_GLOBAL              1 (xrange)
      6 LOAD_CONST               1 (600000)
      9 CALL_FUNCTION            1
     12 CALL_FUNCTION            1
     15 RETURN_VALUE

>>> dis(lambda: list(xrange(600000)))
      0 LOAD_GLOBAL              0 (list)
      3 LOAD_GLOBAL              1 (xrange)
      6 LOAD_CONST               1 (600000)
      9 CALL_FUNCTION            1
     12 CALL_FUNCTION            1
     15 RETURN_VALUE

2 个答案:

答案 0 :(得分:3)

由于迭代器通常不会为您提供前端大小,因此元组和列表都需要使用过度分配策略来处理任意大小的迭代。就目前而言,xrange()对象确实有__len__方法,并且元组和列表使用的_PyObject_LengthHint() function used将利用此方法设置正确的目标大小一次。因此,在这种情况下,list()代码只是巧妙地提高效率,因为它内联迭代以避免NULL比较。

跟我来说明代码;在这种情况下唯一真正的区别是迭代器如何展开并且值被复制。由于list()tuple()对象跟踪不同的信息,因此这些循环在实现中略有不同。参见:

tuple()代码路径使用PyIter_Next(),而list()代码路径则表示不必对NULL进行两次测试。除此之外,循环执行相同的工作量。我认为这是NULL测试,放大超过60万次迭代,考虑到这里的时差。

无论如何,你发现的时差确实不大;在我的机器上重复运行将时间差保持在10%以内(每次list获胜)。时差随着使用的xrange()的大小线性增加。

答案 1 :(得分:1)

我猜这很大程度上取决于你的运行时间。例如。在cpython中,list和tuple函数都用C编码,并且由于列表的使用非常频繁,因此列表方法很可能比元组方法看到更多的优化。

其他实现可能表现不同。