可以建议几个例子来研究 for-loop 与 vectorization 的性能。
示例 #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 循环的每次迭代中使用元素数组的情况。让它在每次迭代中将sine、cosine、tan和sec存储到一列中,即[sin(t) ; cos(t) ; tan(t) ; sec(t)]。
For-loop 代码将是 -
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-loop 在这里没有机会。但是等一下,我们如何再次进行元素分配,例如 for-loop 的示例 #1,像这样 -
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
结论
后一个基准测试结果似乎再次证明,对于高达 10000 的元素,for-loop 获胜,之后矢量化解决方案将是首选。但必须注意的是,这是以编写元素分配为代价的。
最终结论
- 关于决定哪一侧(for循环或矢量化)更好的论点,似乎与黑白图片相差甚远。