Python:多维数组的迭代速度超慢吗?

Pet*_*ann 4 python performance numpy

我必须迭代二维整数数组中的所有项并更改值(根据某些规则,不重要).

我很惊讶python运行时和C#或java运行时之间的性能差异如何.我写了完全错误的python代码(v2.7.2)吗?

import numpy
a = numpy.ndarray((5000,5000), dtype = numpy.int32)
for x in numpy.nditer(a.T):
    x = 123
Run Code Online (Sandbox Code Playgroud)
>python -m timeit -n 2 -r 2 -s "import numpy; a = numpy.ndarray((5000,5000), dtype=numpy.int32)" "for x in numpy.nditer(a.T):" "  x = 123"
2 loops, best of 2: 4.34 sec per loop
Run Code Online (Sandbox Code Playgroud)

例如,C#代码只执行50ms,即python几乎慢100倍!(假设matrix变量已经初始化)

for (y = 0; y < 5000; y++)
for (x = 0; x < 5000; x++)
    matrix[y][x] = 123;
Run Code Online (Sandbox Code Playgroud)

Joe*_*ton 13

是的!在python中迭代numpy数组很慢.(比迭代python列表慢.)

通常,您可以避免直接迭代它们.

如果你能给我们一个你正在改变事物的规则的例子,很有可能它很容易被矢量化.

作为玩具示例:

import numpy as np

x = np.linspace(0, 8*np.pi, 100)
y = np.cos(x)

x[y > 0] = 100
Run Code Online (Sandbox Code Playgroud)

但是,在许多情况下,您必须迭代,或者由于算法(例如,有限差分方法)或者减少临时数组的内存成本.

在这种情况下,看看Cython,Weave或类似的东西.


Sve*_*ach 10

你给出的例子可能是为了将二维NumPy数组的所有项都设置为123.这可以像这样有效地完成:

a.fill(123)
Run Code Online (Sandbox Code Playgroud)

要么

a[:] = 123
Run Code Online (Sandbox Code Playgroud)

  • 并且`numpy.fill`对于示例5000x5000阵列需要50ms,其中等效循环在我正在键入的机器上花费3秒..... (5认同)

ste*_*eha 5

Python是比C或C#更动态的语言。循环如此缓慢的主要原因是,每次循环,CPython解释器都会做一些额外的工作,从而浪费时间:具体地说,它是将名称x与迭代器中的下一个对象绑定在一起,然后在评估赋值时x再次查找名称。

正如@Sven Marnach指出的那样,您可以调用一个方法函数,numpy.fill()并且它很快。该函数是用C或Fortran编译的,它将仅循环遍历numpy.array数据结构的地址并填充值。动态性比Python小得多,这对于这种简单的情况很有用。

但是现在考虑PyPy。在PyPy下运行程序后,JIT将分析您的代码实际在做什么。在此示例中,它指出该名称x仅用于分配,并且可以优化绑定名称的过程。这个例子应该是PyPy极大地加速的例子。PyPy的速度可能会比普通Python快十倍(因此,速度仅为C的十分之一,而不是C的1/100)。

http://pypy.org

据我了解,PyPy暂时不会与Numpy一起使用,因此您不能仅在PyPy下运行现有的Numpy代码。但是,这一天就要到了。

我为PyPy感到兴奋。它提供了希望,我们可以使用一种非常高级的语言(Python)进行编写,而又获得了几乎可以用“便携式汇编语言”(C)进行编写的性能。对于像这样的示例,通过使用来自CPU(SSE2,NEON或其他)的SIMD指令,Numpy甚至可以击败朴素的C代码的性能。对于此示例,使用SIMD,您可以在每个循环中将四个整数设置为123,这将比普通C循环更快。(除非C编译器也使用SIMD优化!考虑到这种情况,很可能会发生这种情况。因此,对于本示例,我们回到“接近C的速度”,而不是更快。但是,我们可以想象到棘手的情况C编译器不够聪明,无法进行优化(未来的PyPy可能会优化)。)

但是暂时不要介意PyPy。如果要使用Numpy,最好学习所有类似的功能numpy.fill(),以加快代码的速度。