MATLAB快速(分量)矢量操作......非常快

时间:2013-05-30 21:18:55

标签: matlab optimization for-loop runtime vectorization

我正在写一些MATLAB脚本,但是,我仍然不明白它是如何工作的“引擎盖下”。考虑以下脚本,它以三种不同的方式使用(大)向量进行一些计算:

  1. MATLAB向量运算;
  2. 对于以相同的计算方式运行的循环很简单;
  3. 优化周期,应该比2更快。因为避免了一些分配和一些任务。
  4. 以下是代码:

    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”循环,其中包含一些操作。

    所以:

    1. 什么是 magic ,以避免第一部分执行如此之快?
    2. 当你写“D = A. * B”时,MATLAB实际上是用“for”循环进行分量计算,还是只是跟踪D包含“bla”和“bla”的乘法?
    3. 修改

      1. 假设我想使用C ++实现相同的计算(可能使用某些库)。 MATLAB的第一种方法是否比在C ++中实现的第三种方法更快? (我会自己回答这个问题,给我一些时间。)
      2. 编辑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用于分配

2 个答案:

答案 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来说都是有用的。