Python 列表与数组:意外性能差异的原因
Python list vs. array: reason for the unexpected performance difference
目前正在学习算法和数据结构
我想我会 运行 一个快速的 timeit.timeit
测试来迭代 list()
中的 2**30 个随机整数列表与 [=14] 中的相同=]格式。
我期待数组首先完成,因为我在其他帖子中看到的 Python 数组的少数无声好处之一是性能
(一开始我误以为list是用链表实现的:谢谢Duncan的指正)
数组应该至少和列表一样快?
import os
import array
l = list(os.urandom(2**30))
a = array.array('I', l)
def test_list():
for i in l:
pass
def test_array():
for i in a:
pass
>>> timeit.timeit(test_array, number=5)
50.08525877200009
>>> timeit.timeit(test_list, number=5)
37.00491460799958
这是我的平台信息:
Python 3.6.5,[GCC 7.3.0] linux x86_64(英特尔 i5 4660)
首先,您将 l
初始化为 2**30 Python int
个值的列表。
然后从列表中初始化 a
以创建一个包含 2**30 个 C 整数的列表。
test_list
遍历 Python int
值的列表。在此过程中没有创建或销毁 Python 个对象,只是每个对象的引用计数器先递增然后递减。
test_array
遍历 C 整数列表,为每个元素创建一个新的 Python int
,然后再次销毁它。这就是数组速度较慢的原因:它创建和销毁 2**30 Python 个对象。
在内部,Python 列表只是指向它包含的对象的指针数组。这意味着迭代列表与迭代数组一样简单和快速。这里的 array
类型将使用更少的内存(或者如果你没有保留列表的话),因为 C 整数比 Python 对象小得多,但每次访问数组必须将 C 值转换为 Python 对象,虽然对象的创建已经过大量优化,但它仍然比仅获取对现有对象的另一个引用要花费更多的时间。
目前正在学习算法和数据结构
我想我会 运行 一个快速的 timeit.timeit
测试来迭代 list()
中的 2**30 个随机整数列表与 [=14] 中的相同=]格式。
我期待数组首先完成,因为我在其他帖子中看到的 Python 数组的少数无声好处之一是性能 (一开始我误以为list是用链表实现的:谢谢Duncan的指正)
数组应该至少和列表一样快?
import os
import array
l = list(os.urandom(2**30))
a = array.array('I', l)
def test_list():
for i in l:
pass
def test_array():
for i in a:
pass
>>> timeit.timeit(test_array, number=5)
50.08525877200009
>>> timeit.timeit(test_list, number=5)
37.00491460799958
这是我的平台信息: Python 3.6.5,[GCC 7.3.0] linux x86_64(英特尔 i5 4660)
首先,您将 l
初始化为 2**30 Python int
个值的列表。
然后从列表中初始化 a
以创建一个包含 2**30 个 C 整数的列表。
test_list
遍历 Python int
值的列表。在此过程中没有创建或销毁 Python 个对象,只是每个对象的引用计数器先递增然后递减。
test_array
遍历 C 整数列表,为每个元素创建一个新的 Python int
,然后再次销毁它。这就是数组速度较慢的原因:它创建和销毁 2**30 Python 个对象。
在内部,Python 列表只是指向它包含的对象的指针数组。这意味着迭代列表与迭代数组一样简单和快速。这里的 array
类型将使用更少的内存(或者如果你没有保留列表的话),因为 C 整数比 Python 对象小得多,但每次访问数组必须将 C 值转换为 Python 对象,虽然对象的创建已经过大量优化,但它仍然比仅获取对现有对象的另一个引用要花费更多的时间。