如何在内存中连续排列现有的 Python 整数列表?

How to arrange an existing Python list of integers consecutively in memory?

以下博客 post 显示如果列表不是随机打乱的,则处理整数列表的速度会更快。由于缓存局部性,未混洗列表的处理速度更快,因为它的相邻元素在内存中相邻。

https://rickystewart.wordpress.com/2013/09/03/why-sorting-an-array-makes-a-python-loop-faster/

我尝试了以下方法,以便重新排序随机列表,使相邻元素在内存中连续。

import copy
a = [i for i in range(1000000)]
shuffle(a)
# Approach 1
a = copy.deepcopy(a)

但是,这并没有提高性能,表明这些项目没有在内存中连续重新排序。

洗牌后我也尝试了以下修改,也没有提高性能。

# Approach 2
a = [x for x in a]

# Approach 3
a = [copy.deepcopy(x) for x in a]

以下方法提高了性能,建议元素在内存中重新排序。

# Approach 4
a = [x+0 for x in a]

我的问题是为什么方法 1 到 3 不对内存中的元素重新排序,而方法 4 却这样做?

是否有与方法 4 不同的推荐方法?

归结为您是否正在创建新对象。事实证明,方法 1 到 3 不会创建新对象,原因如下。

方法 1 和 3:❌

虽然它们看起来不同,但这两种方法是相同的。在整数 (or any immutable builtin type) 上调用 copy.deepcopy 时,copy 模块使用以下方法。

def _deepcopy_atomic(x, memo):
    return x

因此,无论何时深拷贝一个整数,相同的对象都会被returned。同样,深度复制一个整数列表实际上 return 是一个浅拷贝。

from copy import deepcopy

l = [1000]
print(l[0] is deepcopy(l)[0]) # True

方法二:❌

通过 [x for x in a],您可以轻松地创建一个包含完全相同对象的新列表。这是一个完整性检查。

l1 = [1000]
l2 = [x for x in l1]

print(l1[0] is l2[0]) # True

方法四:✅

现在这种方法实际上为大于 256 的整数创建了一个新对象。

x = 1000
print(x is x + 0) # False

最后一句话

虽然最后一种方法是唯一一种实际创建新对象的方法,但我在文档中找不到任何说明这是 属性 语言的内容。所以请记住,这可能是特定于实现的,并且不太可能遇到将 x + 0 优化为始终 return 相同对象的解释。