为什么b.pop(0)比del b[0]慢200多倍?今天深入探究一下

87 阅读1分钟

前天一个同事在一个大循环中使用b.pop(0),结果导致系统雪崩,当时使用del b[0]解决了问题。

今天有空详细研究了一下其根本原因。

对比测量二者的耗时情况:

from timeit import timeit

for _ in range(3):
    t1 = timeit('b.pop(0)', 'b = bytearray(1000000)')
    t2 = timeit('del b[0]', 'b = bytearray(1000000)')
    print(t1 / t2)

结果:使用pop的耗时是使用del的200倍以上。

274.6037053753368
219.38099365582403
252.08691226683823

原因

执行b.pop(0)时,Python将所有元素向后移动。时间复杂度O(n)

而执行del b[0]时,Python只是将对象的起始指针加1。

在这两种情况下,都会调用PyByteArray_Resize来调整大小。当新的大小小于分配大小的一半时,分配的内存将收缩。在del b[0]的情况下,只有这个时候数据才会被复制。因此,这种情况时间复杂度O(1)。

看看相关C源代码

pop方法的实现

而del方法主要调用bytearray_setslice_linear实现