如何高效创建包含一亿零的Python数组?
在Python中,有什么高效的方法来初始化和访问一个大数组的元素呢?
我想在Python里创建一个包含1亿个条目的数组,这些条目是无符号的4字节整数,初始值都设为零。我希望能快速访问这个数组,最好是使用连续的内存。
奇怪的是,NumPy数组的表现似乎很慢。我还有其他可以尝试的替代方案吗?
有一个array.array模块,但我没有找到一个能高效分配1亿个条目的方法。
对评论的回复:
- 我不能使用稀疏数组。因为这个算法会让数组很快变得密集,这样会太慢。
- 我知道Python是解释型语言,但肯定有办法进行快速的数组操作吧?
- 我做了一些性能测试,发现使用NumPy时,每秒大约能进行16万次数组访问(通过索引查找或更新一个元素)。这似乎很慢。
10 个回答
试试这个:
x = [0] * 100000000
在我这台电脑上执行只需要几秒钟,而且访问几乎是瞬间的。
这里提醒一下Python中的整数是怎么工作的:如果你通过下面的方式创建一个列表
a = [0] * K
你需要为这个列表分配内存(sizeof(PyListObject) + K * sizeof(PyObject*)
),还需要为单个整数对象0
分配内存。只要列表中的数字都低于Python用来缓存的那个神奇数字V
,你就没问题,因为这些数字是共享的,也就是说,任何指向一个数字n < V
的名字,实际上都指向同一个对象。你可以用下面的代码找到这个值:
>>> i = 0
>>> j = 0
>>> while i is j:
... i += 1
... j += 1
>>> i # on my system!
257
这意味着,一旦数字的数量超过这个值,你需要的内存就变成了sizeof(PyListObject) + K * sizeof(PyObject*) + d * sizeof(PyIntObject)
,其中d < K
是超过V (== 256)
的整数数量。在64位系统上,sizeof(PyIntObject) == 24
,而sizeof(PyObject*) == 8
,也就是说,最坏情况下的内存消耗是3,200,000,000字节。
使用numpy.ndarray
或array.array
时,初始化后内存消耗是固定的,但你需要为那些透明创建的包装对象付出代价,正如Thomas Wouters所说的那样。也许你应该考虑把更新代码(访问并增加数组中位置的代码)转换成C代码,可以使用Cython或者scipy.weave
来实现。
我做了一些性能测试,结果让我感到非常意外。对于简单的数组访问操作,numpy和array.array的速度比原生Python数组慢了10倍。
需要注意的是,在数组访问时,我进行的操作是这样的:
a[i] += 1
性能测试结果:
[0] * 20000000
- 访问速度:每秒2.3百万次
- 初始化时间:0.8秒
numpy.zeros(shape=(20000000,), dtype=numpy.int32)
- 访问速度:每秒16万次
- 初始化时间:0.2秒
array.array('L', [0] * 20000000)
- 访问速度:每秒17.5万次
- 初始化时间:2.0秒
array.array('L', (0 for i in range(20000000)))
- 访问速度:每秒17.5万次,推测是基于其他array.array的性能测试结果
- 初始化时间:6.7秒