Python列表与数组:意外性能差异的原因

Python列表与数组:意外性能差异的原因,python,python-3.x,data-structures,instructions,Python,Python 3.x,Data Structures,Instructions,我现在正在研究算法和数据结构 我想我应该运行一个快速的timeit.timeit测试,在list()中迭代一个包含2**30个随机整数的列表,与array.array格式的列表进行比较 我本来希望数组首先完成,因为我在其他文章中看到的使用Python数组的少数几个无声好处之一就是性能 (我最初错误地认为该列表是作为链接列表实施的:感谢邓肯的更正) 当然,数组至少应该和列表一样快 import os import array l = list(os.urandom(2**30)) a = arra

我现在正在研究算法和数据结构

我想我应该运行一个快速的
timeit.timeit
测试,在
list()
中迭代一个包含2**30个随机整数的列表,与
array.array
格式的列表进行比较

我本来希望数组首先完成,因为我在其他文章中看到的使用Python数组的少数几个无声好处之一就是性能 (我最初错误地认为该列表是作为链接列表实施的:感谢邓肯的更正)

当然,数组至少应该和列表一样快

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
以下是我的平台信息:
linux x86_64(英特尔i5 4660)上的Python 3.6.5[GCC 7.3.0]

首先初始化
l
到包含2**30个Python
int
值的列表

其次,从列表中初始化
a
,以创建一个包含2**30c整数的列表

test\u list
迭代Python
int
值的列表。在这个过程中,不会创建或销毁Python对象,只是每个对象上的一个引用计数器先递增后递减

test\u array
迭代C整数列表,为每个元素创建一个新的Python
int
,然后再次销毁它。这就是数组速度较慢的原因:它创建和销毁2**30个Python对象


在内部,Python列表只是指向它所包含的对象的指针数组。这意味着遍历列表与遍历数组一样简单和快速。这里的
array
类型将使用更少的内存(或者如果没有保留列表的话),因为C整数比Python对象小得多,但是对数组的每次访问都必须将C值转换为Python对象,虽然对象创建得到了极大的优化,但它仍然需要更多的时间,而不仅仅是获取对现有对象的另一个引用。

首先,您将
l
初始化为包含2**30个Python
int
值的列表

其次,从列表中初始化
a
,以创建一个包含2**30c整数的列表

test\u list
迭代Python
int
值的列表。在这个过程中,不会创建或销毁Python对象,只是每个对象上的一个引用计数器先递增后递减

test\u array
迭代C整数列表,为每个元素创建一个新的Python
int
,然后再次销毁它。这就是数组速度较慢的原因:它创建和销毁2**30个Python对象


在内部,Python列表只是指向它所包含的对象的指针数组。这意味着遍历列表与遍历数组一样简单和快速。这里的
array
类型将使用更少的内存(或者如果没有保留列表的话),因为C整数比Python对象小得多,但是对数组的每次访问都必须将C值转换为Python对象,虽然对象创建得到了极大的优化,但它仍然需要更多的时间,而不仅仅是获取对现有对象的另一个引用。

我们应该对
test\u array
test\u list
做什么进行猜测,还是想告诉我们?不,Python列表不是链表。我不知道你从哪里得到的,但它们是作为数组存储在内部的。我们是不是应该对
test\u数组
test\u列表
做些什么胡乱猜测,还是你想告诉我们?不,Python列表不是链表。我不知道这是从哪里来的,但它们作为数组存储在内部。