缓存未命中。什么时候N
int 对象是连续分配的,保留用于保存它们的内存往往位于连续的块中。因此,按分配顺序爬行列表往往也会访问按顺序、连续、递增顺序保存 int 值的内存。
将其打乱,并且在列表上爬行时的访问模式也是随机的。缓存未命中的情况比比皆是,只要有足够多的不同 int 对象,而它们并不全部适合缓存。
At r==1
, and r==2
,CPython 碰巧将如此小的整数视为单例,因此,例如,尽管列表中有 1000 万个元素,但在r==2
它仅包含(最多)100 个不同的 int 对象。这些数据的所有数据同时放入缓存中。
但除此之外,您可能会获得越来越多、越来越不同的 int 对象。当访问模式是随机的时,硬件缓存变得越来越无用。
说明:
>>> from random import randint, seed
>>> seed(987987987)
>>> for x in range(1, 9):
... r = 10 ** x
... js = [randint(1, r) for _ in range(10_000_000)]
... unique = set(map(id, js))
... print(f"{r:12,} {len(unique):12,}")
...
10 10
100 100
1,000 7,440,909
10,000 9,744,400
100,000 9,974,838
1,000,000 9,997,739
10,000,000 9,999,908
100,000,000 9,999,998