【问题标题】:Speed for filling a matrix in python vs matlab在 python 与 matlab 中填充矩阵的速度
【发布时间】:2013-12-03 10:44:21
【问题描述】:

我正在测试 Python 与 Matlab 相比的速度。我决定转向 Python 是因为它有很多优势,但我想比较一下速度,看看在这方面有什么不同。

我测试了一些 for 循环来填充 1000 x 1000 矩阵,如下所示:

from numpy import *

sizeM = 1000
y = zeros((sizeM,sizeM))
x = 4
tic = time.clock()

for i in range(sizeM):
    for j in range(sizeM):
        y[i,j] = cos(i*j) + i * sin(x**2);

toc = time.clock()
time = toc-tic

time 以这种方式为 5.93 秒。但在 Matlab 中,使用以下代码只需要 0.11 秒

tic
sizeM = 1000;
y = zeros(sizeM);
x =4;
for i = 1:sizeM
     for j = 1:sizeM
         y(i,j) = cos(i*j) + i * sin(x^2);
     end
end

toc

我的问题是:

是这样吗?

Matlab 在执行嵌套 for 循环时是否比 Python 快?还是我在这里做错了什么?

感谢您的帮助。

【问题讨论】:

  • 一般来说,速度增益不足以从 matlab 迁移到 python。 -- 另请注意,在 matlab 代码中,您实际上初始化了大矩阵,而在 python 代码中,这超出了时间范围。 -- 此外,向量化 matlab 操作可能会更快。
  • 我完全同意你的看法。由于许多其他争论,我已经决定转向 python,这只是我想测试的一件事。
  • 为什么您没有得出结论 Python 在计算三角表达式时比 Matlab 慢?这似乎至少与您的测试得出的结论一样合理。
  • 这不一定是真的。我用三角表达式测试了其他一些没有嵌套循环的代码,在某些情况下 python 更快......
  • 您还应该使用xrange 而不是range。使用range,您将在内存中为每个循环显式创建sizeM 元素列表,这对内部循环尤其不利。 MATLAB 没有为基本语法 for i=1:N 执行此操作

标签: python performance matlab python-2.7 numpy


【解决方案1】:

我希望您知道在这两种语言中您都应该编写矢量化代码!

  1. 我相信,Matlab 有一个即时加速器,它可能会启动这样的表达式,我不确定如果你在内部循环中调用自己的函数会发生什么。
  2. 循环本身并不是万能的,大多数情况下,最内层循环的内容更为重要。因此,嵌套循环是更慢还是更快的整个问题可能通常是错误的问题。
  3. NumPy 是为与 数组 一起工作而编写的。给它这样的标量会增加很多开销,如果你真的想使用浮点标量(你不应该因为你可以向量化操作),你不妨使用math.sin...

不管怎样,对比一下向量化的代码:

i, j = np.ogrid[:1000,:1000] # or whatever else you want to use
y = np.cos(i * j) + i * np.sin(x**2)

也许您可以进一步优化它,但这不重要。


由于似乎讨论可能从这里开始,我不确定 matlab 的开销对于标量是多少,可能非常小(在成功的 JIT 下肯定是这样),但这是为了解释为什么这个代码片段使用 numpy 可能会很慢。请不要进行语言比较...

可以肯定地说,特别是如果 JIT 在 matlab 中发挥作用,则有必要在 NumPy 中尝试更加努力地矢量化(或移植到在这两种语言中都适用的编译语言)对速度敏感的代码。

【讨论】:

  • 在老式 Matlab (pre JIT) 上开发的向量化技能很好地移植到 numpy。 numpy 实际上更好,因为它有更强大的广播规则。 Octave 也需要这些技能。 Octave 像广播一样变得麻木只是一两个版本。恐怕 Matlab JIT 会培养出整整一代没有多维数组思考能力的 Matlab 程序员。
  • ogrid 向量化使速度提高了 100 倍。
  • 在此代码中将 numpy.sin 替换为 math.sin 可以在我的测试机器上提高 8.8 到 10.5 倍的时间
  • 是的,使用较新/未来的 numpy 版本应该会更好,但有开销。
【解决方案2】:

答案是你真的没有在这里测试嵌套循环。 大部分时间不会花在循环上,而是花在评估循环中的表达式上。

如果你想测试循环和矩阵的填充,你可以做一些更简单的事情,比如:

from numpy import *

sizeM = 1000
y = zeros((sizeM,sizeM))
x = 4
tic = time.clock()

for i in range(sizeM):
    for j in range(sizeM):
        y[i,j] = 1;

toc = time.clock()
time = toc-tic

相比:

sizeM = 1000;
y = zeros(sizeM);
x =4;
tic
for i = 1:sizeM
     for j = 1:sizeM
         y(i,j) = 1;
     end
end
toc

【讨论】:

  • 谢谢。是的,我这样做了,你是对的。但它是一样的。 Python:0.21 秒,Matlab:0.008 秒
  • 当然,如您所知,Dennis,Matlab 程序员可能只会写y=1 并继续做一些更有趣的事情。让编译器(和 Python 程序员)担心编写嵌套循环。
  • @jorgeca:与 Matlab 版本相比,我在该赋值语句的 rhs 上计算了 9 个额外字符。那些可怜的 numpython 程序员正把他们可怜的小手指穿到骨头里。
  • @HighPerformanceMark 我认为y=1 不会创建一个包含 1000 个数组的数组;)但是,matlab 更简洁,因为您不需要一直输入np.。另一方面,Python 的禅宗说:“命名空间是一个很棒的主意——让我们做更多这样的事!” :)
  • y(:)=1 可以解决问题。但是@jorgeca,您不认为您可以编写看起来非常好的代码令人不快,却发现它实际上非常低效,因为您使用了错误的命名空间?请参阅上面的 numpy.sinmath.sin 评论。
【解决方案3】:

JIT compiler 有助于优化 MATLAB for 循环(尽管 Python 也支持某些形式的 JIT 编译)。您可以使用feature accel offfeature accel on 禁用/启用 JIT 加速器,然后使用以下代码再次测试。 蟒蛇:

import time    
sizeM = 1000

tic = time.clock()

for i in range(sizeM):
   for j in range(sizeM):
      pass

toc = time.clock()
time = toc-tic
print time

Matlab 测试1:

sizeM = 1000;
tic
for i = 1:sizeM
   for j = 1:sizeM
     ;
   end
end
toc

Matlab 测试2:

sizeM = 1000;
tic
for i = [1:sizeM]
   for j = [1:sizeM]
     ;
   end
end
toc

你还可以比较range(sizeM)xrange(sizeM)的速度,如果你喜欢的话。

【讨论】:

  • 也许您可以在答案中添加类似结论的内容?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-23
  • 2018-01-23
  • 2013-09-02
  • 2012-09-25
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
相关资源
最近更新 更多