deque.popleft()
和list.pop(0)
似乎返回相同的结果。它们之间是否有任何性能差异?为什么?
答案 0 :(得分:21)
deque.popleft()比list.pop(0)更快,因为deque已被优化为大约在O(1)中执行popleft(),而list.pop(0)需要O(n)(参见deque objects)。
_collectionsmodule.c中的deque和listobject.c for list的注释和代码提供了解释性能差异的实现见解。即deque对象“由双向链表组成”,它有效地优化了两端的追加和弹出,而列表对象甚至不是单链表,而是C数组(指向元素的指针(见{{3}) }和Python 2.7 listobject.h#l22),这使得它们适用于元素的快速随机访问,但在删除第一个元素后需要O(n)时间重新定位所有元素。
对于Python 2.7和3.5,这些源代码文件的URL是:
https://hg.python.org/cpython/file/2.7/Modules/_collectionsmodule.c
https://hg.python.org/cpython/file/3.5/Modules/_collectionsmodule.c
使用%timeit时,deque.popleft()和list.pop(0)之间的性能差异大约为4,因为双端队列和列表具有相同的52个元素并且当增长到1000倍时他们的长度是10 ** 8。测试结果如下。
import string
from collections import deque
%timeit d = deque(string.letters); d.popleft()
1000000 loops, best of 3: 1.46 µs per loop
%timeit d = deque(string.letters)
1000000 loops, best of 3: 1.4 µs per loop
%timeit l = list(string.letters); l.pop(0)
1000000 loops, best of 3: 1.47 µs per loop
%timeit l = list(string.letters);
1000000 loops, best of 3: 1.22 µs per loop
d = deque(range(100000000))
%timeit d.popleft()
10000000 loops, best of 3: 90.5 ns per loop
l = range(100000000)
%timeit l.pop(0)
10 loops, best of 3: 93.4 ms per loop
答案 1 :(得分:9)
是否有性能差异?
是。 deque.popleft()
是O(1)
- 一个恒定的时间操作。虽然list.pop(0)
为O(n)
- 线性时间操作:列表越大则需要的时间越长。
为什么?
CPython列表实现是基于数组的。 pop(0)
从列表中删除第一项,并且需要转移左len(lst) - 1
项以填补空白。
deque()
实现使用双向链表。无论deque多大,deque.popleft()
都需要一个恒定的(有限的以上)操作次数。
答案 2 :(得分:5)
是的,如果你有一个很长的列表或双端队列,这是相当可观的。列表中的所有元素都连续放置在内存中,因此如果删除任何元素,则所有后续元素必须向左移动一个位置 - 因此,在列表开头删除或插入元素所需的时间与列表的长度。另一方面,deque是专门构造的,允许在 端快速插入或移除(通常通过在双端队列的开始处允许“空”存储器位置,或者环绕以使得deque占用的内存段的末尾可以包含实际上被认为是在deque开头的元素。)
比较这两个片段的效果:
spans