【问题标题】:Is deque from the collections module really 100 times faster at prepending than list in Python?来自集合模块的双端队列真的比 Python 中的列表快 100 倍吗?
【发布时间】:2016-01-20 12:21:08
【问题描述】:

我的代码有问题吗?使用collections 模块中的deque 而非常规列表对简单函数进行计时时,我的速度提高了 100 倍。

>>> from collections import deque as dl
>>> import cProfile
>>> 
>>> def l(i):
...     l = ['0','1','2','3','4','5','6']
...     while i:
...         l.insert(0,'9')
...         i -= 1
... 
>>> def d(i):
...     l = dl('0123456')
...     while i:
...         l.appendleft('9')
...         i -= 1
... 
>>> cProfile.run('l(100000)')
         100004 function calls in 4.480 seconds

[...]

>>> cProfile.run('d(100000)')
         100004 function calls in 0.031 seconds

如果我的代码没问题,那么使用列表的意义何在?为什么不完全切换到deque

【问题讨论】:

  • 那么普通的.append()...呢?
  • 根据文档,列表“针对快速固定长度操作进行了优化”;在这件事上将它们与deques 进行比较并得出结论认为它们毫无意义是不公平的。
  • 嗯,有三个可能的答案: 1. 还有一些你还没有想到的操作列表更快; 2. 除了操作速度之外,使用列表还有其他好处(例如,您是否比较了内存​​占用?);或者 3. 开发人员只是没有意识到他们可以一直使用双端队列。老实说,最后一个似乎最不可能!
  • 简而言之,这是一个快速的项目访问。必须多次将某些内容插入列表的情况很少见。当你这样做时,是时候切换到队列或双端队列了。甚至并非总是如此。列表可以很好地附加和获取数据,这是它们最常见的用途。
  • 如果 Deque 是列表的替代品,你不认为我们现在会改用它吗???

标签: python performance list deque cprofile


【解决方案1】:

来自 Python 文档:

双端队列是堆栈和队列的概括(名称发音为“deck”,是“双端队列”的缩写)。双端队列支持线程安全、内存高效的从双端队列的任一侧追加和弹出,在任一方向上的 O(1) 性能大致相同。

虽然列表对象支持类似的操作,但它们针对快速固定长度操作进行了优化,并且会为 pop(0) 和 insert(0, v) 操作带来 O(n) 的内存移动成本,这些操作会同时改变列表的大小和位置底层数据表示。

Deques 支持迭代、酸洗、len(d)、reversed(d)、copy.copy(d)、copy.deepcopy(d)、使用 in 运算符的成员资格测试以及下标引用,例如 d[-1] .索引访问在两端都是 O(1),但在中间慢到 O(n)。对于快速随机访问,请改用列表。

...

现在不同的是,list是用固定大小的内存块(数组)实现的,而deque是用双链表实现的。

这意味着列表必须根据插入新项目的位置重新分配内存并制作数据副本,追加时除外。

但随机访问(索引)对他们来说非常快。

双端队列不存在这样的问题,因为在插入时,只需要纠正指针以在给定位置插入新节点。

但是查找数据(插入或随机访问的位置 - 索引)需要对双端队列进行迭代。

Deques 也是线程安全的,但除非您必须处理端点,即队列列表的使用属性仍然是您最好的朋友。

双队列在每个项目中使用更多的内存,因为它们在每个项目中至少存储了两个整数(指针)。

还有分割双端队列的问题。它可以通过使用旋转方法切换双端队列的端点来手动完成。获取 N 个项目,然后旋转回来。

从 Python 文档中查看 del 如何仅针对一项实现:

rotate() 方法提供了一种实现双端队列切片和删除的方法。例如,del d[n] 的纯 Python 实现依赖于 rotate() 方法来定位要弹出的元素:

def delete_nth(d, n):
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

我认为这对你来说已经足够了。顺便说一句,您的 Q 几乎与以下内容重复:

How are deques in Python implemented, and when are they worse than lists?

【讨论】:

  • 糟糕,我忘了真正回答你:你的代码很好! :D :D 所以,是的,它是一个贡献。
猜你喜欢
  • 2019-04-30
  • 2012-09-15
  • 2020-04-19
  • 2016-01-23
  • 2014-06-22
  • 1970-01-01
  • 2014-10-14
  • 2016-10-14
  • 2010-09-23
相关资源
最近更新 更多