如何在内存中连续排列现有的 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 相同对象的解释。
以下博客 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 相同对象的解释。