带/不带循环的Matlab性能

时间:2014-08-25 17:37:24

标签: performance matlab loops

我已经阅读THIS SO 的评论,认为Matlab在for循环中不再缓慢(c.f。link)。

我以前在学习期间经常使用Matlab,我记得通过总是找到一个不涉及过多循环的解决方案来节省多少时间(使用reshaperepmat或{{{ 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我们应该尽可能地避免循环。

现在,我正在寻找一个反例。

3 个答案:

答案 0 :(得分:4)

问题在于不同的人认为“慢”。

当MATLAB for循环从“令人难以置信的极度缓慢”变为“比矢量化版本慢8倍”时,将会有

  1. 有些人惊呼:“哇,MATLAB在循环中不再慢!”
  2. 其他人说,“使用循环时MATLAB变得更好。但仍然不好,但可忍受。”
  3. 有些人发现“好吧,8因素仍然是一个巨大的减速。一直向量化”
  4. 最后得出的结论是:“即使在矢量化代码上,C仍然更快.MATLAB不会削减它。”
  5. 在我看来,MATLAB在循环中仍然很慢(猜测我是第三组)并且你应该尽可能地进行矢量化(除非可读性受到影响)。 仅仅因为它在过去甚至更慢,并没有使当前的表现更好。

    此外,MATLAB还有其他一些弱点:https://stackoverflow.com/a/17933146/1974021

答案 1 :(得分:2)

为了提高效果,可能会建议您使用for-loopvectorization进行研究。

示例#1

这只是计算多个元素的正弦的非常基本的计算。这些元素的数量是多种多样的,以评估手头的问题。灵感来自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

示例#2

让我们考虑在for循环的每次迭代中使用元素数组的情况。让它在每次迭代中将sinecosinetansec存储到一列中,即[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元素,之后的矢量化解决方案将是首选。但必须指出的是,这是以编写元素分配为代价的。


最终结论

  1. 关于决定哪一方(for-loop或矢量化)更好的论点,似乎它远非黑白照片。

答案 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提供成功分析它的机会;)