为什么 a.insert (0,0)比[0:0] = [0]慢得多?

使用列表的 insert函数比使用片分配实现同样的效果要慢得多:

> python -m timeit -n 100000 -s "a=[]" "a.insert(0,0)"
100000 loops, best of 5: 19.2 usec per loop


> python -m timeit -n 100000 -s "a=[]" "a[0:0]=[0]"
100000 loops, best of 5: 6.78 usec per loop

(注意,a=[]只是设置,因此 a开始为空,但随后增长到100,000个元素。)

起初我以为可能是属性查找或函数调用开销大小的问题,但是在末尾插入显示这是可以忽略不计的:

> python -m timeit -n 100000 -s "a=[]" "a.insert(-1,0)"
100000 loops, best of 5: 79.1 nsec per loop

为什么可能更简单的专用“插入单个元素”函数要慢得多?

我也可以复制它 回复:

from timeit import repeat


for _ in range(3):
for stmt in 'a.insert(0,0)', 'a[0:0]=[0]', 'a.insert(-1,0)':
t = min(repeat(stmt, 'a=[]', number=10**5))
print('%.6f' % t, stmt)
print()


# Example output:
#
# 4.803514 a.insert(0,0)
# 1.807832 a[0:0]=[0]
# 0.012533 a.insert(-1,0)
#
# 4.967313 a.insert(0,0)
# 1.821665 a[0:0]=[0]
# 0.012738 a.insert(-1,0)
#
# 5.694100 a.insert(0,0)
# 1.899940 a[0:0]=[0]
# 0.012664 a.insert(-1,0)

我在 Windows 1064位上使用 Python 3.8.132位。
It 在 Linux 64位上使用 Python 3.8.164位。

2316 次浏览

我想可能是因为他们忘了在 list.insert中使用 memmove。如果你看看 密码 list.insert用来移动元素,你会发现它只是一个手动循环:

for (i = n; --i >= where; )
items[i+1] = items[i];

而片分配路径 使用 memmove上的 list.__setitem__:

memmove(&item[ihigh+d], &item[ihigh],
(k - ihigh)*sizeof(PyObject *));

memmove通常有很多优化,比如利用 SSE/AVX 指令。