我已经阅读THIS对 SO 的评论,认为Matlab在for循环中不再缓慢(c.f。link)。
我以前在学习期间经常使用Matlab,我记得通过总是找到一个不涉及过多循环的解决方案来节省多少时间(使用reshape
,repmat
或{{{ 1}})。
所以上面的这篇文章引起了我的注意,我很快写了这个:
arrayfun
输出:
clear all; T = linspace(0,1,1e6);
tic
i = 0;
for t = T
i = i + 1; y(i) = sin(t);
end
toc
clear all; T = linspace(0,1,1e6);
tic
i = 0;
y = zeros(numel(T), 1);
for t = T
i = i + 1; y(i) = sin(t);
end
toc
clear all; T = linspace(0,1,1e6);
tic
y = sin(T);
toc
我还尝试切换Elapsed time is 1.741640 seconds.
Elapsed time is 1.400412 seconds.
Elapsed time is 0.004076 seconds.
功能......
accel
但每次,即使对于更复杂的矩阵操作,使用原生Matlab函数的矢量化版本总是更快。
也许我错过了一些重要的观点,或者我对我的观点仍然是正确的:使用Matlab我们应该尽可能地避免循环。
现在,我正在寻找一个反例。
答案 0 :(得分:4)
问题在于不同的人认为“慢”。
当MATLAB for循环从“令人难以置信的极度缓慢”变为“比矢量化版本慢8倍”时,将会有
在我看来,MATLAB在循环中仍然很慢(猜测我是第三组)并且你应该尽可能地进行矢量化(除非可读性受到影响)。 仅仅因为它在过去甚至更慢,并没有使当前的表现更好。
此外,MATLAB还有其他一些弱点:https://stackoverflow.com/a/17933146/1974021
答案 1 :(得分:2)
为了提高效果,可能会建议您使用for-loop
与vectorization
进行研究。
这只是计算多个元素的正弦的非常基本的计算。这些元素的数量是多种多样的,以评估手头的问题。灵感来自this screenshot link。
基准代码
num_runs = 1000;
N_arr = [ 1000 10000 100000 1000000];
%// Warm up tic/toc.
for k = 1:100
tic(); elapsed = toc();
end
for k = 1:numel(N_arr)
N = N_arr(k);
tic
for runs=1:num_runs
out_f1 = zeros(1,N);
for t = 1:N
out_f1(t) = sin(t);
end
end
t_forloop = toc/num_runs;
tic
for runs=1:num_runs
out_v1 = sin(1:N);
end
t_vect = toc/num_runs;
end
<强>结果
----------- Datsize(N) = 1000 -------------
Elapsed time with for-loops - 7.1826e-05
Elapsed time with vectorized code - 8.3601e-05
----------- Datsize(N) = 10000 -------------
Elapsed time with for-loops - 0.00068531
Elapsed time with vectorized code - 0.00045043
----------- Datsize(N) = 100000 -------------
Elapsed time with for-loops - 0.0074613
Elapsed time with vectorized code - 0.0053368
----------- Datsize(N) = 1000000 -------------
Elapsed time with for-loops - 0.077707
Elapsed time with vectorized code - 0.053255
请注意,这些结果与timeit
结果一致(此处未显示代码和结果)。
<强>结论强>
for-loops
元素案例中尽快忘记10000
。 让我们考虑在for循环的每次迭代中使用元素数组的情况。让它在每次迭代中将sine
,cosine
,tan
和sec
存储到一列中,即[sin(t) ; cos(t) ; tan(t) ; sec(t)]
。
For循环代码将是 -
out_f1 = zeros(4,N);
for t = 1:N
out_f1(:,t) = [sin(t) ; cos(t) ; tan(t) ; sec(t)];
end
矢量化代码 -
out_v1 = [sin(1:N); cos(1:N) ; tan(1:N); sec(1:N)];
<强>结果
----------- Datsize(N) = 100 -------------
Elapsed time with for-loops - 0.00011861
Elapsed time with vectorized code - 6.0569e-05
----------- Datsize(N) = 1000 -------------
Elapsed time with for-loops - 0.0011867
Elapsed time with vectorized code - 0.00036786
----------- Datsize(N) = 10000 -------------
Elapsed time with for-loops - 0.011819
Elapsed time with vectorized code - 0.0025536
----------- Datsize(N) = 1000000 -------------
Elapsed time with for-loops - 1.2329
Elapsed time with vectorized code - 0.33383
修改案例
人们可以很容易地得出结论:for循环在这里没有机会。但是等一下,我们如何再次进行元素分配,就像例如#1 for for-loop case一样 -
out_f1 = zeros(4,N);
for t = 1:N
out_f1(1,t) = sin(t);
out_f1(2,t) = cos(t);
out_f1(3,t) = tan(t);
out_f1(4,t) = sec(t);
end
现在,这使用空间局部性,因此使用相同的竞争矢量化代码将是 -
out_v1 = [sin(1:N) cos(1:N) tan(1:N) sec(1:N)]';
此测试用例的这些修改代码的基准测试结果是 -
----------- Datsize(N) = 100 -------------
Elapsed time with for-loops - 3.1987e-05
Elapsed time with vectorized code - 6.9778e-05
----------- Datsize(N) = 1000 -------------
Elapsed time with for-loops - 0.00027976
Elapsed time with vectorized code - 0.00036804
----------- Datsize(N) = 10000 -------------
Elapsed time with for-loops - 0.0029712
Elapsed time with vectorized code - 0.0024423
----------- Datsize(N) = 100000 -------------
Elapsed time with for-loops - 0.031113
Elapsed time with vectorized code - 0.028549
----------- Datsize(N) = 1000000 -------------
Elapsed time with for-loops - 0.32636
Elapsed time with vectorized code - 0.28063
<强>结论强>
后一个基准测试结果似乎再次证明,对于for循环获胜的最多10000
元素,之后的矢量化解决方案将是首选。但必须指出的是,这是以编写元素分配为代价的。
答案 2 :(得分:1)
使用实际循环索引,jit-compiler了解你的循环:
clear all; T = linspace(0,1,1e6);
tic
y = zeros(numel(T), 1);
for idx=1:numel(T)
y(idx) = sin(T(idx));
end
toc
这样的代码要快得多。优化基于代码分析,编写清晰的代码并为matlab提供成功分析它的机会;)