【问题标题】:Why is Octave's function call overhead so much larger than both Matlab's and Python's?为什么 Octave 的函数调用开销比 Matlab 和 Python 的要大得多?
【发布时间】:2015-10-02 21:48:33
【问题描述】:

我有两段结构相同的 Python 和 Octave 代码。但是,使用 numpy 和 scipy 实现的 Python 版本要快约 5 倍。我对代码做了一个概要分析,发现 Octave 代码中的罪魁祸首是 6 个函数在一个循环中重复调用了数千次。这些函数只计算数值表达式,例如cos,cosh,所以我很惊讶它们消耗了多少时间(作为参考,这两个代码都在 2 秒内运行。)

我在网上研究了这个奇怪的现象并阅读了paper,它表明 Octave 中的函数开销,即函数开始执行函数体中的实际函数代码并随后清理它所需的设置,大约是比 Matlab 大 30 倍,比 Python 大约 100 倍。

这种情况让我很困惑——从 Octave 调用函数怎么可能this比在其他两种类似语言中调用函数慢得多?此外,除了将函数本身复制并粘贴到循环体中之外,还有什么方法可以弥补这种速度下降?

编辑:我已经从我的代码中发布了主 for 循环。这是对多个方程的牛顿法的迭代实现,所以我不确定如何对其进行矢量化。

for k = 1:10    
  for l = 1:50
    % matrix of derivatives of equations with respect to variables
    a = [dEq1_dq1(p1, p2, q1, q2, i, j), dEq1_dq2(p1, p2, q1, q2, i, j); dEq2_dq1(p1, p2, q1, q2, i, j), dEq2_dq2(p1, p2, q1, q2, i, j)];

    % vector of equations
    b = [Eq1(p1, p2, q1, q2, i, j); Eq2(p1, p2, q1, q2, i, j)];

    % solution to ax=b
    x = a \ b;

    % iteratively update q
    q1 -= beta*x(1);
    q2 -= beta*x(2);
  endfor

  for l = 1:50
    a = [dEp1_dp1(p1, p2, q1, q2, i, j), dEp1_dp2(p1, p2, q1, q2, i, j); dEp2_dp1(p1, p2, q1, q2, i, j), dEp2_dp2(p1, p2, q1, q2, i, j)];
    b = [Ep1(p1, p2, q1, q2, i, j); Ep2(p1, p2, q1, q2, i, j)];
    x = a \ b;

    p1 -= beta*x(1);
    p2 -= beta*x(2);
  endfor
endfor

...

% derivatives of implicit equations with respect to variables
function val = dEp1_dp1(p1, p2, q1, q2, i, j)
  % symmetric
  if mod(i, 2) == 1
    val = p1/(2*cos(p1/2)**2)+tan(p1/2);
  % anti-symmetric
  else
    val = tan(p1/2)/(p1**2)-1/(2*p1*cos(p1/2)**2);
  endif
end

...

function val = Ep1(p1, p2, q1, q2, i, j)    
  if mod(i, 2) == 1
    val = p2*tanh(p2/2)+p1*tan(p1/2);
  else
    val = (1/p2)*tanh(p2/2)-(1/p1)*tan(p1/2);
  endif
end

...

【问题讨论】:

  • 所有 3 种语言都是解释性语言,在函数调用时会产生一些开销。考虑到 Python 和 Matlab 都比 Octave 进行了更好的优化,我并不感到惊讶,因为它们是更大的项目(更大的用户群,更多的开发发生等)。特别是,Matlab 使用即时 (JIT) 加速器,在许多情况下会更快。至于如何避免这个问题:矢量化你的代码,除非绝对必要,否则不要使用循环。
  • @rth 感谢您提供有见地的信息。不幸的是,我的代码是牛顿法的迭代实现(有几个方程),所以我不确定如何对其进行矢量化。这种情况有什么可能的解决方案吗?如果我发布我的代码也会有帮助吗?

标签: performance matlab function optimization octave


【解决方案1】:

比较语言之间的性能是一件棘手的事情。 Octave 会立即告诉您应该对代码进行矢量化处理。这就是语言的设计目的。 Python 将他的代码编译成字节码,这将允许优化。 Matlab 有同样的 JIT。但不是八度。 Octave 将完全按照您编写的方式执行操作,并且一次读取您的程序一行。这意味着如果您不编写好的代码,您的性能将会受到影响。

虽然进行函数调用可能会产生很大的开销(我没有检查您的数字),但如果您只进行几个函数调用,这并不是那么重要。您经常会处理大型数组,因此实际的“科学”计算应该会导致您的性能问题(当然,除非您没有编写正确的 Octave 程序并使用不必要的循环)。

您提到的函数coscosh 将接受向量,因此无需使用for 循环。

【讨论】:

  • 感谢您的快速回复。这实际上是我第一次在 Octave 中编写大型程序——我过去主要使用 Python。我知道,由于编译器对 CPU 进行了低级优化,向量化显着加快了代码速度,但我不确定在这种情况下如何向量化我的代码——这是牛顿方法对多个方程的迭代实现。我已将我的代码编辑到上面的问题中,如果您能看一下,我将不胜感激。 :)
  • @VedaadShakib 实际上矢量化您的代码是一个不同的问题。它可能需要我没有的数值分析知识。可能需要注意的是,并非所有语言都适合一切。如果你不能向量化你的代码,而且它确实需要大量的迭代和许多函数调用,那么 Octave 将不是解决你问题的一个糟糕的选择。但是你可以使用 liboctave,它有一个非常好的 C++ 接口。
  • 好的,我可能会考虑“获取”一个 Matlab 版本并在那里试一试。无论如何,谢谢!
猜你喜欢
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-23
  • 2013-08-01
  • 1970-01-01
相关资源
最近更新 更多