如果与在for循环中继续语句 [英] If vs Continue statement in a for loop
问题描述
for循环,如果
>,for循环中的所有代码都被包含在声明。例如:
对于p = 1:长度(数组)
如果数组(p)== 1% /测试正面条件
%//通用代码在这里
%//只有在p == 1
end时才会执行;
end;
使用进行相等性测试的速度会更快吗if
语句,并执行内部代码(如果为true),或者测试不等式,然后使用continue语句,如:
对于p = 1:长度(数组)
如果数组(p)〜= 1%//对于条件
continue, %//跳过,如果
结束;
%//通用代码在这里
%//只有在p == 1
end时才会执行;
或者,这两种方法都没有什么区别,也就是说它优化到执行相同的结果吗?
编辑:有趣的是,在推荐代码之后,后者似乎更快一些 - 如果有人愿意解释,那将是很棒的! (毕竟,最好是它的逻辑是相同的,但是要执行额外的指令)
解决方案理论上,不应该存在在你提出的两个方法之间的性能差异,因为每一次循环都要评估 if
语句,但是让我们仔细看看一些性能分析( timeit
)。我在R2014a到R2015b版本中有一些测试。
对于每个测试,我创建一个数组 p
不同大小的1和0相同的数字,并随机分配0和1的顺序。
$ $ $ $ $创建随机零和大小n
p = mod(randperm(n),2);
对于第一次测试,我
这可能是由于JIT编译器加速了连续多次执行的指令块所致。通过将分支逻辑与 continue
粘在一起,您将根据条件更改程序的流程,并更改每次循环中运行的指令。这显然阻止了JIT编译。
R2014b
与R2014a相似。
R2015b(
总结
在旧版本的MATLAB(R2015a及更早版本)中,如果执行版本, 正如你所指出的那样, continue
语句阻止了JIT加速,导致启用JIT时(默认情况下)更快。随着在R2015b中引入新的执行引擎,所有的代码被JIT加速,因此差异已经消失。
循环,而不是这里显示的简单乘法,差异完全消失)。
如果
语句仍然很快 。这可能是由于实际调用 continue
的开销。这个差异在事物的宏伟计划中可以忽略不计。而且,如果for循环的整体性能真的取决于这个差异,则意味着循环的内容的速度非常快,而瓶颈是 for
循环本身,你应该考虑向量化你的代码(例如,如果我把一个魔术(3)
c $ c> for
I have a for
loop in Matlab, and all the code inside the for loop is enclosed in an if
statement. For example :
for p = 1:length(array)
if array(p) == 1 %// Test positive for condition
%// Generic code here that
%// Only executes if p == 1
end;
end;
Is it faster to have test for equality using an if
statement, and execute the interior code if true, or, to test for inequality and then use a continue statement, such as :
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;
Or, does it make no difference either way i.e. its optimized to the same result on execution?
As its only a micro-optimization its not terribly important - but I'm curious to know!
EDIT: Interestingly, after profiling the code as recommended, the latter seems to be fractionally faster - if anybody would care to explain that would be great! (After all, at best its the same logic but with extra instructions to be executed)
In theory, there should not be a performance difference between the two methods that you have proposed because the if
statement has to be evaluated every time through the loop regardless, but let's take a closer look with some profiling (timeit
). I have some tests below on versions R2014a through R2015b.
For each of these tests, I create an array p
of varying sizes of an equal number of 1's and 0's and randomized the order of 0's and 1's.
%// Creates random zeros and ones of size n
p = mod(randperm(n),2);
For the first test, I disabled the JIT compiler feature('JIT', 'off')
and the second test I enabled the JIT compiler feature('JIT', 'on')
.
The script I used for all versions of MATLAB was:
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
R2014a
As you can see here, continue
and the if
statement have very similar performance with no JIT acceleration turned on. However, when you turn on the acceleration (MATLAB's default), only the if
statement seems to be accelerated. The speed of the continue
approach remains relatively unchanged. As a result, the if
statement would execute faster.
This is likely due to the fact that the JIT compiler accelerates blocks of instructions that are executed many times in a row. By sticking the branching logic with a continue
in there, you are changing the flow of the program depending upon a condition and this changes the instructions that are run each time through the loop. This is apparently preventing JIT compilation.
R2014b
Similar to R2014a.
R2015a
Similar to R2014a.
R2015b (new execution engine introduced)
Unfortunately, in R2015b it doesn't seem that you can disable JIT in the same way (if anyone knows how, let me know and I'll update) so both of these plots have acceleration enabled, but it appears that the new execution engine removes the differences in execution time that the JIT compiler had previously created. This is because the new execution engine is able to JIT compile all code (including, obviously the continue
)
From the MATLAB docs:
Just-in-Time Compilation of All MATLAB Code
The redesigned MATLAB execution engine uses JIT compilation of all MATLAB code, whereas the execution engine previously used JIT compilation in some cases. The JIT compilation generates native machine level code that is optimized for the MATLAB code being executed and for the specific hardware platform.
The performance benefit of JIT compilation is greatest when MATLAB code is executed additional times and can re-use the compiled code. This happens in common cases such as for-loops or when applications are run additional times in a MATLAB session with at least some of the application’s MATLAB files remaining unmodified between subsequent runs.
Summary
In older versions of MATLAB (R2015a and earlier), the continue
statement prevented JIT acceleration causing the if
version to execute faster when JIT was enabled (by default). With the introduction of the new execution engine in R2015b, all code is JIT accelerated and as such, the difference has effectively vanished.
As you noted though, the if
statement is just barely faster still. This is likely due to the overhead of actually calling continue
. This difference is negligible in the grand scheme of things. Furthermore, if the overall performance of your for loop really depends on this difference, it means that the speed of the contents of the loop is very fast and your bottleneck is the for
loop itself and you should consider vectorizing your code (i.e. if I put a magic(3)
call within my for
loop instead of the simple multiplication shown here, the difference completely disappears).
这篇关于如果与在for循环中继续语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!