我在Matlab中有一个if
循环,for循环中的所有代码都包含在for p = 1:length(array)
if array(p) == 1 %// Test positive for condition
%// Generic code here that
%// Only executes if p == 1
end;
end;
语句中。例如:
if
使用for p = 1:length(array)
if array(p) ~= 1 %// Test negative for condition
continue; %// Skip if negative
end;
%// Generic code here that
%// Only executes if p == 1
end;
语句测试相等性是否更快,如果为true则执行内部代码,或者,测试不等式,然后使用continue语句,例如:
Class Library
或者,两种方式都没有区别,即它在执行时优化到相同的结果?
因为它唯一的微观优化并不是非常重要 - 但我很想知道!
编辑:有趣的是,在按照推荐的方式对代码进行分析后,后者似乎分数更快 - 如果有人愿意解释这将是伟大的! (毕竟,最好是相同的逻辑,但需要执行额外的指令)
答案 0 :(得分:19)
理论上,你提出的两种方法之间不应该存在性能差异,因为无论如何都必须在每次循环中评估if
语句,但让我们仔细看看进行一些分析(timeit
)。我在R2014a到R2015b版本下面进行了一些测试。
对于这些测试中的每一个,我创建了一个不同大小的相同数量的1&0和0的数组p
,并按0和#1的顺序随机化。 39; S
%// Creates random zeros and ones of size n
p = mod(randperm(n),2);
对于第一个测试,我disabled the JIT compiler 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]);
%// Disable JIT
feature('JIT', 'off')
runtests(sz, 1, ['JIT Disabled ', V(1).Release]);
%// Enable JIT
feature('JIT', 'on')
runtests(sz, 2, ['JIT Enabled ', V(1).Release]);
%// Match up ylims on all plots
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
正如您在此处所看到的,continue
和if
语句的非常性能相似但没有启用JIT加速。但是,当您打开加速度(MATLAB的默认值)时,仅 if
语句似乎会加速。 continue
方法的速度保持相对不变。因此,if
语句执行得更快。
这可能是由于JIT编译器加速连续多次执行的指令块。通过在其中粘贴分支逻辑continue
,您将根据条件更改程序的流程,这会更改每次循环运行的指令。这显然是在阻止JIT编译。
与R2014a类似。
与R2014a类似。
不幸的是,在R2015b中,您似乎无法以相同的方式禁用JIT(如果有人知道如何,让我知道并且我会更新),所以这两个图都启用了加速,但是似乎新的执行引擎消除了JIT编译器之前创建的执行时间的差异。这是因为新的执行引擎能够JIT编译所有代码(包括显然是continue
)
来自MATLAB文档:
即时编译所有MATLAB代码
重新设计的MATLAB执行引擎使用所有MATLAB代码的JIT编译,而执行引擎以前在某些情况下使用JIT编译。 JIT编译生成本机机器级代码,该代码针对正在执行的MATLAB代码和特定硬件平台进行了优化。
当MATLAB代码执行额外的次数并且可以重复使用已编译的代码时,JIT编译的性能优势最大。这种情况发生在常见的情况下,例如for循环,或者在MATLAB会话中运行应用程序时,其中至少某些应用程序的MATLAB文件在后续运行之间保持不变。
在早期版本的MATLAB(R2015a及更早版本)中,continue
语句阻止了JIT加速,导致if
版本在启用JIT时执行得更快(默认情况下)。随着R2015b中新执行引擎的引入,所有代码都是JIT加速的,因此,差异实际上已经消失了。
正如您所指出的那样,if
语句只是勉强更快。这可能是由于实际调用continue
的开销。在宏观方案中,这种差异可以忽略不计。此外,如果for循环的整体性能确实取决于这种差异,则意味着循环的内容的速度非常快,并且您的瓶颈是{ {1}}循环本身,您应该考虑对代码进行矢量化(即如果我在for
循环中调用magic(3)
调用而不是此处显示的简单乘法,则差异将完全消失。)