使用Python在内存中分配大型数组

4
代码
import array, itertools
a = array.array('B', itertools.repeat(0, 3715948544))

在我的计算机上运行几乎需要7分钟(6m44s)。该计算机具有8 Gb的RAM,运行Linux和CPython 3.4.3。如何使用Python标准库更快地获取一个类似于数组的对象,其中包含1字节无符号整数条目?Numpy可以立即分配它(不到1毫秒)。


1
为什么要预分配它? - Two-Bit Alchemist
你应该放弃使用标准库,而是使用numpy - Cody Piersall
3
等等,如果你知道NumPy可以解决你的问题,为什么还要问这个问题呢? - user2357112
2
@user2357112,我希望尽可能减少外部依赖,因为我之后会分发这段代码,而且不想麻烦自己设置很多库。 - Pastafarianist
2
什么使用了30亿个值,但与科学相关的程度不足以满足Numpy的极低要求?你能在Anaconda中分发它吗? - Nick T
显示剩余3条评论
3个回答

6
a = array.array('B', [0]) * 3715948544

序列乘法,类似于创建一个巨大的零列表。请注意,您想要执行的任何操作都可能与创建它的初始尝试一样缓慢。


这在我的电脑上大约需要2秒钟。谢谢! - Pastafarianist

3

如果您真的无法使用NumPy,可以尝试使用内置的bytearray来达到多远的效果:

a = bytearray(3715948544)

这应该在最多几秒钟内完成。


这个速度大约和另一个答案中的序列乘法一样快,大约1.95秒。谢谢! - Pastafarianist
@Pastafarianist 这仍然存在与序列乘法相同的问题 - 在创建了巨大的缓冲区之后,你无法真正对其进行有用的操作,否则会变得非常慢。 - Sven Marnach
我刚刚测试了bytearrayarray.arraynumpy。在我的特定情况下,bytearray是最快的,array.array紧随其后,而numpy则慢了近2倍。我正在运行一个特定的计算,其中这个数组基本上是一个巨大的计数器:我读取一个值,加上1,写回去,然后检查是否超过了阈值。使用bytearray每次迭代大约需要7.5秒,array.array大约需要7.75秒,而numpy则需要14.6秒。 - Pastafarianist
@Pastafarianist:你考虑过使用collections.Counter吗?或者只是一个普通的字典?7.5秒的数字听起来像是你没有使用到数组中的所有单元格。(要么,也许你是指每个读取/增加/写入/检查循环需要7.5秒,这太慢了。) - user2357112
1
@Pastafarianist:以那个速度,使用几乎所有的条目将需要大约14小时,而且这还是在没有任何计数超过1的情况下。如果平均值为10,那就要花上近一周的时间。你可能想要考虑使用Cython,或者直接用C语言来编写。听起来7分钟的启动延迟已经成了一个无法接受的问题,所以运行时间从14小时到一周可能并不是一个很好的选择。 - user2357112
显示剩余2条评论

1

一开始我认为 numpy 会更快,但正如 Sven 所指出的那样,对于10000来说,bytearray 也非常快。在30亿上试试你的运气吧。

In [1]: import numpy as np

In [2]: import array, itertools

In [3]: %timeit array.array('B', itertools.repeat(0, 10000))
1000 loops, best of 3: 456 µs per loop

In [4]: %timeit np.zeros(10000, dtype='uint8')
1000000 loops, best of 3: 924 ns per loop

In [5]: %timeit bytearray(10000)
1000000 loops, best of 3: 328 ns per loop

2
Numpy当然是最好的解决方案,因为它是唯一一个在创建数组后允许你实际操作数组的解决方案。 - Sven Marnach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接