我正在写一些MATLAB脚本,但是,我仍然不明白它是如何工作的“引擎盖下”。考虑以下脚本,它以三种不同的方式使用(大)向量进行一些计算:
以下是代码:
N = 10000000;
A = linspace(0,100,N);
B = linspace(-100,100,N);
C = linspace(0,200,N);
D = linspace(100,200,N);
% 1. MATLAB Operations
tic
C_ = C./A;
D_ = D./B;
G_ = (A+B)/2;
H_ = (C_+D_)/2;
I_ = (C_.^2+D_.^2)/2;
X = G_ .* H_;
Y = G_ .* H_.^2 + I_;
toc
tic
X;
Y;
toc
% 2. Simple cycle
tic
C_ = zeros(1,N);
D_ = zeros(1,N);
G_ = zeros(1,N);
H_ = zeros(1,N);
I_ = zeros(1,N);
X = zeros(1,N);
Y = zeros(1,N);
for i = 1:N,
C_(i) = C(i)/A(i);
D_(i) = D(i)/B(i);
G_(i) = (A(i)+B(i))/2;
H_(i) = (C_(i)+D_(i))/2;
I_(i) = (C_(i)^2+D_(i)^2)/2;
X(i) = G_(i) * H_(i);
Y(i) = G_(i) * H_(i)^2 + I_(i);
end
toc
tic
X;
Y;
toc
% 3. Opzimized cycle
tic
X = zeros(1,N);
Y = zeros(1,N);
for i = 1:N,
X(i) = (A(i)+B(i))/2 * (( C(i)/A(i) + D(i)/B(i) ) /2);
Y(i) = (A(i)+B(i))/2 * (( C(i)/A(i) + D(i)/B(i) ) /2)^2 + ( (C(i)/A(i))^2 + (D(i)/B(i))^2 ) / 2;
end
toc
tic
X;
Y;
toc
我知道人们总是试图对计算进行矢量化,因为MATLAB构建在矩阵/向量之上(因此,现在,它并不总是最佳选择),所以我期待像:
C = A .* B;
比以下更快:
for i in 1:N,
C(i) = A(i) * B(i);
end
我不期待的是即使在上面的脚本中它实际上更快,尽管我使用的第二和第三种方法只经历一个周期,而第一种方法执行很多向量操作(理论上,每次都是“for”循环)。这迫使我得出结论,MATLAB有一些 magic 允许(例如):
C = A .* B;
D = C .* C;
运行更快而不是单个“for”循环,其中包含一些操作。
所以:
修改
编辑2
根据要求,这里有实验运行时:
第1部分:0.237143
第2部分:4.440132 其中0.195154用于分配
第3部分:2.280640 其中0.057500用于分配
没有JIT:
第1部分:0.337259
第2部分:149.602017 其中0.033886用于分配
第3部分:82.167713 其中0.010852用于分配
答案 0 :(得分:3)
第一个是最快的,因为矢量化代码可以很容易地解释为少量优化的C ++库调用。 Matlab还可以在更高的级别对其进行优化,例如,在其核心中使用优化的G*H+I
而不是mul_add(G,H,I)
替换add(mul(G,H),I)
。
第二个无法轻松转换为C ++调用。它必须被解释或编译。脚本语言最现代的方法是JIT编译。 Matlab JIT编译器不是很好,但并不意味着它必须如此。我不知道MathWorks为什么不改进它。因此,#2表现得如此之慢,以至于#1更快,即使它会产生更多的数学"操作
Julia语言被发明为Matlab表达式和C ++速度之间的折衷。相同的非向量化代码(julia vs matlab)的工作速度非常快,因为JIT编译非常好。
答案 1 :(得分:0)
关于性能优化,我按照'for' loop vs vectorization in MATLAB中提到的两种方法使用探查器关注@memyself建议。
出于教育目的,尝试使用数值算法是有意义的,对于其他任何我认可的libraries来说都是有用的。