高效的Python数组有1亿个零?

Jos*_*ian 24 python arrays performance

在Python中初始化和访问大型数组元素的有效方法是什么?

我想在Python中创建一个包含1亿个条目的数组,无符号的4字节整数,初始化为零.我想要快速数组访问,最好是连续的内存.

奇怪的是,NumPy阵列的表现似乎很慢.我可以尝试其他替代品吗?

array.array模块,但我没有看到有效分配1亿条目块的方法.

回复评论:

  • 我不能使用稀疏数组.这个算法太慢了,因为阵列变得非常快.
  • 我知道Python被解释了,但肯定有办法快速进行数组运算吗?
  • 我进行了一些分析,并且每秒使用NumPy获得大约160K的数组访问(按索引查找或更新元素).这似乎很慢.

Jos*_*ian 33

我做了一些分析,结果完全违反直觉.对于简单的数组访问操作,numpy和array.array比本机Python数组慢10倍.

请注意,对于数组访问,我正在执行以下形式的操作:

a[i] += 1
Run Code Online (Sandbox Code Playgroud)

简介:

  • [0]*20000000

    • 访问:2.3M /秒
    • 初始化:0.8秒
  • numpy.zeros(shape =(20000000,),dtype = numpy.int32)

    • 访问:160K /秒
    • 初始化:0.2s
  • array.array('L',[0]*20000000)

    • 访问:175K /秒
    • 初始化:2.0s
  • array.array('L',(0表示范围内的i(20000000)))

    • 访问:175K /秒,大概是基于其他array.array的配置文件
    • 初始化:6.7s

  • @Joseph:实际测量它的+1,而不是依赖互联网上点击箭头的一群匿名随机人的意见.;) (9认同)
  • 这是因为索引Python列表是一个非常快速的操作:它只是获取内部数组中已有的对象.`array.array`和`numpy.array`对象不包含Python对象,因此存储在数组中的实际数据类型需要在访问时进行转换.它是更低,更低内存使用和实际连续数据块的代价. (8认同)
  • @Joseph:正如我在原来的答案中所说的那样,很难说不知道你在做什么.numpy有非常有效的矩阵运算,但是如果你真的只是随机访问和增量,那些对你没有帮助.避免访问单个元素的"减速"的方法是不进行单独访问:) (2认同)
  • 哦,我可能还应该指出,Python 整数列表不是 4 字节无符号整数数组,而且它也不是连续的。(相反,它将是一个连续的指向分散在各处的 Python 对象的指针数组。)这是否足够好完全取决于您的实际用例。 (2认同)

Tor*_*rek 13

只是提醒一下Python的整数是如何工作的:如果你通过说明分配一个列表

a = [0] * K
Run Code Online (Sandbox Code Playgroud)

你需要list(sizeof(PyListObject) + K * sizeof(PyObject*))的内存和单个整数对象的内存0.只要列表中的数字保持在VPython用于缓存的幻数之下,就可以了,因为它们是共享的,即任何指向数字的名称都指向n < V完全相同的对象.您可以使用以下代码段找到此值:

>>> i = 0
>>> j = 0
>>> while i is j:
...    i += 1
...    j += 1
>>> i # on my system!
257 
Run Code Online (Sandbox Code Playgroud)

这意味着一旦计数超过这个数,你需要的内存是sizeof(PyListObject) + K * sizeof(PyObject*) + d * sizeof(PyIntObject),d < K上面的整数数在哪里V (== 256).在64位的系统,sizeof(PyIntObject) == 24并且sizeof(PyObject*) == 8,即,最坏的情况下内存消耗32亿个字节.

numpy.ndarrayarray.array,内存消耗为初始化之后维持恒定,但你付了透明地创建,如托马斯·沃特斯说,包装对象.也许你应该考虑将更新代码(访问和增加数组中的位置)转换为C代码,或者使用Cythonscipy.weave.


Mar*_*ers 7

试试这个:

x = [0] * 100000000
Run Code Online (Sandbox Code Playgroud)

在我的机器上执行只需几秒钟,接近即时.


Tho*_*ers 5

您不太可能找到比numpys更快的东西array。数组本身的实现与 C 语言中的实现一样高效(并且与 C 语言基本相同array.array,只是更有用。)

如果您想加快代码速度,则必须这样做。尽管数组的实现很高效,但从 Python 代码访问它会产生一定的开销;例如,索引数组会生成整数对象,这些对象必须动态创建。numpy提供了许多在 C 中有效实现的操作,但是如果没有看到实际代码的性能不如您想要的,就很难提出任何具体的建议。


Tri*_*tan 5

如果你无法对你的计算进行矢量化,那么Python/Numpy会很慢.Numpy很快,因为矢量化计算的发生频率低于Python.核心numpy函数都是用C或Fortran编写的.因此sum(a),不是具有许多访问的python循环,它是单个低级别C调用.

Numpy的Performance Python演示页面有一个很好的例子,有不同的选项.通过使用较低级别的编译语言Cython或使用矢量化函数(如果可行),您可以轻松获得100倍的增长. 这篇博文显示使用Cython增加了43倍的numpy用例.