前天一个同事在一个大循环中使用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实现