考试
使用 MatLab 2013b I 和 Intel Xeon 3.6GHz + 16GB RAM,我运行下面的代码进行分析。我区分了 3 种方法,只考虑了一维数组,即向量。方法 1 和 2 已经使用列向量和行向量进行了测试,即 (n,1) 和 (1,n)。
方法 1 (M1R, M1C)
a = zeros(1,n);
方法 2 M2R、M2C
a = NaN(1,n);
方法 3 (M3)
a(n) = 0;
结果
时序结果和元素数量已在图时序1D 中以双对数刻度绘制。
如图所示,第三种方法的分配几乎与向量大小无关,而另一种方法稳步增加,表明向量的隐式定义。
讨论
MatLab 使用 JIT (Just in time) 做了很多代码优化,即在运行时进行代码优化。因此,提出运行速度更快的代码部分是由于编程(无论是否优化始终相同)还是由于优化是一个有效的问题。要测试此优化,可以使用 feature('accel','off') 关闭。再次运行代码的结果相当有趣:
结果表明,现在方法 1 对于行向量和列向量都是最优的。方法 3 的行为类似于第一个测试中的其他方法。
结论
优化内存预分配是无用的,而且浪费时间,因为 MatLab 无论如何都会为您优化。
请注意,内存应该是预先分配的,但您执行它的方式并不重要。预分配内存的性能很大程度上取决于 MatLab 的 JIT 编译器是否选择优化您的代码。这完全取决于 .m 文件的所有其他内容,因为编译器当时会考虑代码块然后尝试优化(它甚至有内存,因此多次运行文件可能会导致执行率更低 -时间)。与之后执行的计算相比,考虑到性能,内存预分配通常是一个非常短的过程
在我看来,应该使用方法 1 或方法 2 预先分配内存,以维护可读的代码并使用 MatLab 帮助建议的功能,因为这些是未来最有可能改进的功能。
使用的代码
clear all
clc
feature('accel','on')
number1D=30;
nn1D=2.^(1:number1D);
timings1D=zeros(5,number1D);
for ii=1:length(nn1D);
n=nn1D(ii);
% 1D
tic
a = zeros(1,n);
a(randi(n,1))=1;
timings1D(1,ii)=toc;
fprintf('1D row vector method1 took: %f\n',timings1D(1,ii))
clear a
tic
b = zeros(n,1);
b(randi(n,1))=1;
timings1D(2,ii)=toc;
fprintf('1D column vector method1 took: %f\n',timings1D(2,ii))
clear b
tic
c = NaN(1,n);
c(randi(n,1))=1;
timings1D(3,ii)=toc;
fprintf('1D row vector method2 took: %f\n',timings1D(3,ii))
clear c
tic
d = NaN(n,1);
d(randi(n,1))=1;
timings1D(4,ii)=toc;
fprintf('1D row vector method2 took: %f\n',timings1D(4,ii))
clear d
tic
e(n) = 0;
e(randi(n,1))=1;
timings1D(5,ii)=toc;
fprintf('1D row vector method3 took: %f\n',timings1D(5,ii))
clear e
end
logtimings1D = log10(timings1D);
lognn1D=log10(nn1D);
figure(1)
clf()
hold on
plot(lognn1D,logtimings1D(1,:),'-k','LineWidth',2)
plot(lognn1D,logtimings1D(2,:),'--k','LineWidth',2)
plot(lognn1D,logtimings1D(3,:),'-.k','LineWidth',2)
plot(lognn1D,logtimings1D(4,:),'-','Color',[0.6 0.6 0.6],'LineWidth',2)
plot(lognn1D,logtimings1D(5,:),'--','Color',[0.6 0.6 0.6],'LineWidth',2)
xlabel('Number of elements (log10[-])')
ylabel('Timing of each method (log10[s])')
legend('M1R','M1C','M2R','M2C','M3','Location','NW')
title({'Various methods of pre-allocation in 1D','nr. of elements vs timing'})
hold off
笔记
包含c(randi(n,1))=1
; 除了将值 1 分配给预分配数组中的随机元素之外,不要做任何事情,以便使用该数组来稍微挑战 JIT 编译器。这些线不会显着影响预分配测量,即它们不可测量并且不影响测试。