如果与在for循环中继续语句 [英] If vs Continue statement in a for loop

查看:270
本文介绍了如果与在for循环中继续语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Matlab中我有一个 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆