Python: 多维数组迭代速度非常缓慢吗?

2024-05-16 14:23:34 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我很惊讶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
>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

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

for (y = 0; y < 5000; y++)
for (x = 0; x < 5000; x++)
    matrix[y][x] = 123;

Tags: 代码inimportnumpyfor规则整数数组
3条回答

是的!在python中迭代numpy数组是很慢的。(也比遍历python列表慢。)

通常,避免直接遍历它们。

如果你能给我们一个例子,你正在改变的东西的基础上,有一个很好的机会,它很容易矢量化。

作为一个玩具示例:

import numpy as np

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

x[y > 0] = 100

但是,在许多情况下,由于算法(例如,有限差分法)的原因,或者为了减少临时数组的内存开销,必须进行迭代。

在这种情况下,请查看CythonWeave或类似的内容。

您给出的示例可能是要将二维NumPy数组的所有项设置为123。这可以像这样高效地完成:

a.fill(123)

或者

a[:] = 123

Python是一种比C或C更具动态性的语言。循环如此缓慢的主要原因是,在每次传递时,CPython解释器都要做一些额外的工作,这会浪费时间:特别是,它将名称x与迭代器中的下一个对象绑定,然后当它计算赋值时,必须再次查找名称x

正如@Sven Marnach所指出的,您可以调用方法函数numpy.fill(),它很快。这个函数是用C或Fortran编译的,它将简单地循环numpy.array数据结构的地址并填充值。比Python动态性差得多,这对于这个简单的例子来说是很好的。

但现在想想派比。在PyPy下运行程序后,JIT将分析代码实际在做什么。在这个例子中,它注意到名称x除了赋值之外没有任何用途,它可以优化绑定名称。这个例子应该是PyPy速度非常快的一个例子;PyPy的速度可能是普通Python的十倍(所以只有C的十分之一快,而不是1/100快)。

http://pypy.org

据我所知,PyPy暂时还不能与Numpy一起工作,因此您还不能在PyPy下运行现有的Numpy代码。但这一天就要到了。

我对派比很兴奋。它提供了一种希望,即我们可以用一种非常高级的语言(Python)编写代码,同时也可以获得用“可移植汇编语言”(C)编写代码的性能。对于像这样的例子,Numpy甚至可以通过使用来自CPU的SIMD指令(SSE2、NEON或其他什么)来击败朴素C代码的性能。对于这个例子,使用SIMD,可以在每个循环中将四个整数设置为123,这比普通的C循环要快。(除非C编译器也使用了SIMD优化!想想看,这个案子很可能就是这样。所以我们回到了“接近C的速度”,而不是这个例子中更快的速度。但我们可以想象更棘手的情况,即C编译器不够聪明,无法进行优化,而未来的PyPy可能会这样做。)

但现在别管皮比了。如果您将使用Numpy,那么最好学习像numpy.fill()这样的所有函数,它们可以加快您的代码速度。

相关问题 更多 >