摘要

本文主要讲述非并行的MATLAB代码加速的原则。

 

1. 尽量删除for-loop操作

很多代码中尽量将for-loop操作删除,取而代之的是向量化的操作,比如向量乘法,元素点乘,矩阵运算等等。

 

%% 采用循环操作
clear all;
tic 
A = 0:0.000001:10;
B = 0:0.000001:10;
Z = zeros(size(A));
y = 0;
for i = 1:10000001
    Z(i) = sin(0.5*A(i))*exp(B(i)^2);
    y = y + Z(i);
end
disp(['采用循环操作的代码段的计算结果:',num2str(y)]);
disp(['采用循环操作的代码段的运行时间:',num2str(toc)]);
%% 不采用循环操作
clear all;
tic 
A = 0:0.000001:10;
B = 0:0.000001:10;
Z = zeros(size(A));
y = 0;
y = sin(0.5*A)*exp(B.^2)';
disp(['删除循环操作的代码段的计算结果:',num2str(y)]);
disp(['删除循环操作的代码段的运行时间:',num2str(toc)]);

 

 

 

测试结果

 

采用循环操作的代码段的计算结果:-1.304248469509501e+48
采用循环操作的代码段的运行时间:0.81621
删除循环操作的代码段的计算结果:-1.304248469509501e+48
删除循环操作的代码段的运行时间:0.53451

 

 

 

2. 尽量删除if-else操作

既然每一个都得进行判断,那就大家一块儿判断。

 

%% 采用逻辑判断
clear all
tic 
A = 0:0.000001:10;
B = 0:0.000001:10;
Z = zeros(size(A));
y = 0;
for i = 1:10000001
    if(A(i)<0.1)
        A(i)=0.1;
    elseif(A(i)>0.9)
        A(i)=0.9;
    end
    Z(i) = sin(0.5*A(i))*exp(B(i)^2);
    y = y + Z(i);
end
disp(['采用逻辑判断的代码段的计算结果:',num2str(y)]);
disp(['采用逻辑判断的代码段的运行时间:',num2str(toc)]);
%% 删除逻辑判断
clear all
tic 
A = 0:0.000001:10;
B = 0:0.000001:10;
Z = zeros(size(A));
y = 0;
A = max(A,0.1);
A = min(A,0.9);
y = sin(0.5*A)*exp(B.^2)';
disp(['删除逻辑判断的代码段的计算结果:',num2str(y)]);
disp(['删除逻辑判断的代码段的运行时间:',num2str(toc)]);

 

 

 

测试结果

 

采用逻辑判断的代码段的计算结果:5.875930789448835e+47
采用逻辑判断的代码段的运行时间:0.77513
删除逻辑判断的代码段的计算结果:5.875930789448889e+47
删除逻辑判断的代码段的运行时间:0.29838

 

 

 

3. 尽量避免动态内存调整

尽量避免动态的内存调整,尽量使用预先分配好的内存,这样会提高代码的运行效率。

 

%% 采用内存调整
tic 
x(1) = 8;
x(2) = 10;
x(3) = 11;
x(4) = 20;
disp(['采用内存调整的代码段的运行时间:',num2str(toc)]);
%% 删除内存调整
tic
y = zeros(4,1);
x(1) = 8;
x(2) = 10;
x(3) = 11;
x(4) = 20;
disp(['删除内存调整的代码段的运行时间:',num2str(toc)]);

测试结果

 

 

采用内存调整的代码段的运行时间:2.6447e-05
删除内存调整的代码段的运行时间:5.5262e-06

 

 

 

4. 尽量采用逐列访问

根据MATLAB编译器对内存的操作情况,矩阵在存储的时候,对内存的操作是逐列访问的,因此,程序上如果也采用这种访问方式,必将使得硬件操作速度更快,代码效率更高效。

 

%% 采用逐行访问
clear all;
A = rand(300, 300, 40, 40);
B = zeros(300, 300, 40, 40);
tic 
for i = 1:300
    for j = 1:300
        B(i,j,:,:) = 2.5*A(i,j,:,:);
    end
end
toc
disp(['采用逐列访问的代码段的运行时间:',num2str(toc)]);
%% 采用逐列访问
clear all;
A = rand(300, 300, 40, 40);
B = zeros(300, 300, 40, 40);
tic 
for j = 1:300
    for i = 1:300
        B(i,j,:,:) = 2.5*A(i,j,:,:);
    end
end
toc
disp(['采用逐行访问的代码段的运行时间:',num2str(toc)]);

 

 

 

测试结果

 

采用逐行访问的代码段的运行时间:12.3208
采用逐列访问的代码段的运行时间:10.1274

 

 

 

5. 其他MATLAB非并行加速建议

矩阵如果存在大量的零元素(百分之五十以上),则采用稀疏矩阵的形式存储;

另外,尽量避免不必要的IO操作。