我在Python和Octave中有两段结构完全相同的代码。但是,使用numpy和scipy实现的Python版本速度提高了约5倍。我做了代码的配置文件,我发现Octave代码中的主要罪魁祸首是6个函数在循环中重复调用了数千次。这些函数仅计算数值表达式,例如cos,cosh,所以我很惊讶他们消耗了多少时间(作为参考,两个代码都在2秒内运行。)
我在网上研究了这个奇怪的现象并阅读了paper,它显示了Octave中的函数开销,即函数开始执行函数体内的实际函数代码所需的设置和清理之后,它比Matlab的大约30倍,比Python的大约100倍。
这种情况让我感到非常困惑 - 从Octave调用函数怎么可能这个比调用另外两种类似语言中的函数慢得多?此外,除了将函数本身复制并粘贴到循环体中之外,还有什么方法可以解决这种速度降低的问题吗?
编辑:我已经从我的代码中发布了主要的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
...
答案 0 :(得分:4)
比较语言之间的性能是一件棘手的事情。 Octave会马上告诉你,你应该对你的代码进行矢量化。这就是语言的设计目标。 Python将他的代码编译成字节代码,这将允许优化。 Matlab有JIT,它也是如此。但不是Octave。 Octave将完全按照您所写的内容执行,并且会一次读取您的程序。这意味着如果您没有编写好的代码,您的表现将会受到影响。
虽然进行函数调用可能会有很大的开销(我没有检查你的数字),但如果你只进行一些函数调用那就不那么重要了。你经常会处理大型阵列,所以它是实际的" sciency"应该导致性能问题的计算(当然,除非您没有编写正确的Octave程序并使用不必要的循环)。
您提到的功能cos
和cosh
将接受一个向量,因此无需使用for循环。