理论上来说,您提出的两种方法在性能上不应该有差异,因为无论如何每次循环都必须评估if
语句,但让我们通过一些分析(timeit
)来更仔细地查看。我下面列出了一些在版本R2014a到R2015b上的测试结果。
对于这些测试中的每一个,我创建了一个数组p
,它包含相同数量的1和0,并随机改变了0和1的顺序。
%// Creates random zeros and ones of size n
p = mod(randperm(n),2);
在第一次测试中,我禁用了JIT编译器feature('JIT', 'off')
,而在第二次测试中,我启用了JIT编译器feature('JIT', 'on')
。
我在所有版本的MATLAB中使用的脚本如下:
function tests()
V = ver;
sz = round(linspace(100, 10000,100));
hfig = figure('Position', [0 0 900 400]);
feature('JIT', 'off')
runtests(sz, 1, ['JIT Disabled ', V(1).Release]);
feature('JIT', 'on')
runtests(sz, 2, ['JIT Enabled ', V(1).Release]);
ax = findall(hfig, 'type', 'axes');
ylims = get(ax, 'ylim');
ylims = cat(1, ylims{:});
set(ax, 'ylim', [0, max(ylims(:,2))])
end
function out = runtests(sz, n, label)
times1 = zeros(numel(sz), 1);
times2 = zeros(numel(sz), 1);
for k = 1:numel(sz)
p = mod(randperm(sz(k)),2);
times1(k) = timeit(@()continueit(p));
p = mod(randperm(sz(k)),2);
times2(k) = timeit(@()ifit(p));
end
subplot(1,2,n)
plots(sz, cat(2, times1, times2))
title(label)
end
function plots(sz, times)
plot(sz, times * 1000)
legend({'Continue', 'If'})
xlabel('Size of Array')
ylabel('Execution Time (ms)')
end
function continueit(p)
c = 1;
for k = 1:numel(p)
if p(k) ~= 1
continue;
end
c = c * k;
end
end
function ifit(p)
c = 1;
for k = 1:numel(p)
if p(k) == 1
c = c * k;
end
end
end
R2014a
如您所见,continue
和 if
语句在未启用 JIT(MATLAB 默认设置)时具有非常相似的性能。然而,当您启用加速功能时,只有 if
语句似乎可以被加速。使用 continue
的方法的速度仍然保持相对不变。因此,if
语句会执行得更快。
![enter image description here](https://istack.dev59.com/qAPv6.webp)
这可能是由于 JIT 编译器加速连续执行的指令块。通过在其中插入带有 continue
的分支逻辑,您正在根据条件更改程序流程,并更改每次通过循环运行的指令。这显然会阻止 JIT 编译。
R2014b
与 R2014a 相似。
![enter image description here](https://istack.dev59.com/azJvt.webp)
R2015a
与 R2014a 相似。
![enter image description here](https://istack.dev59.com/xQkrD.webp)
R2015b (新执行引擎引入)
不幸的是,R2015b 似乎无法用同样的方式禁用 JIT(如果有人知道如何做,请告诉我,我会更新)。因此,这两个图都启用了加速功能,但似乎新的执行引擎消除了 JIT 编译器以前创建的执行时间差异。这是因为新的执行引擎能够 JIT 编译 所有 代码(包括显然的 continue
)。
来自 MATLAB 文档:
对所有 MATLAB 代码进行即时编译
重新设计的 MATLAB 执行引擎使用所有 MATLAB 代码的 JIT 编译,而以前的执行引擎仅在某些情况下使用 JIT 编译。JIT 编译生成本地机器级别代码,该代码针对正在执行的 MATLAB 代码和特定的硬件平台进行优化。
JIT 编译的性能优势最大的情况是当 MATLAB 代码被多次执行并且可以重复使用编译的代码时。这在常见情况下发生,例如 for 循环或在 MATLAB 会话中运行应用程序时,在后续运行之间至少有一些应用程序的 MATLAB 文件保持不变。
![enter image description here](https://istack.dev59.com/EML5l.webp)
概述
在旧版本的MATLAB(R2015a及更早版本)中,continue
语句会阻止JIT加速,导致启用JIT(默认情况下)时if
语句版本的执行速度更快。随着新执行引擎在R2015b中的引入,所有代码都可以进行JIT加速,因此,差异已经基本消失。
不过,正如您所指出的,if
语句仍然略微更快。这可能是由于实际调用continue
的开销。在整个大局中,这种差异非常小。此外,如果您的for循环的整体性能确实取决于这种差异,那么这意味着循环中的内容非常快,并且瓶颈是for
循环本身,您应该考虑向量化您的代码(即,如果我在我的for
循环中放一个magic(3)
调用而不是这里显示的简单乘法,差异将完全消失)。