views:

537

answers:

6

In Perl, a conditional can be expressed either as

if (condition) { do something }

or as

(condition) and do { do something }

Interestingly, the second way seems to be about 10% faster. Does anyone know why?

+10  A: 

I've deparsed it, and it really shouldn't be faster. The opcode tree for the first is

LISTOP (0x8177a18) leave [1] 
    OP (0x8176590) enter 
    COP (0x8177a40) nextstate 
    LISTOP (0x8177b20) scope 
        OP (0x81779b8) null [174] 
        UNOP (0x8177c40) dofile 
            SVOP (0x8177b58) const [1] PV (0x81546e4) "something"

The opcode tree for the second is

LISTOP (0x8177b28) leave [1] 
    OP (0x8176598) enter 
    COP (0x8177a48) nextstate 
    UNOP (0x8177980) null 
        LISTOP (0x8177ca0) scope 
            OP (0x81779c0) null [174] 
            UNOP (0x8177c48) dofile 
                SVOP (0x8177b60) const [1] PV (0x81546e4) "something"

I really don't see how the latter could be faster. It does an opcode more!

Leon Timmermans
+2  A: 

According to Benchmark, the second is slightly slower. Possibly it has something to do with the condition, but here's results for a very simple case:


use Benchmark;

timethese(10000000, {
    'if' => '$m=5;if($m > 4){my $i=0;}',
    'and' => '$m=5; $m > 4 and do {my $i =0}',
});

Results:


Benchmark: timing 10000000 iterations of Name1, Name2...
     if:  3 wallclock secs ( 2.94 usr +  0.01 sys =  2.95 CPU) @ 3389830.51/s (n=10000000)
     and:  3 wallclock secs ( 3.01 usr +  0.01 sys =  3.02 CPU) @ 3311258.28/s (n=10000000)

shelfoo
A 2% difference like that is inside the flutter of benchmarking. Running the benchmark a few times shows a variation up to .10 usr time which is enough to reverse the above situation. Only on Perl 5.005 do I see a consistent edging out of "and" over "if".
Schwern
+12  A: 

Which just goes to show, if you don't know how to do proper code profiling, don't be doing this stuff. The speed difference of these two methods are within the same Big O() speed (As proven by @Leon Timmermans opcode analyisis) - the benchmarks are just going to show differences based on other local conditions, not necessarily your code.

@Svante said the "and" was faster, and @shelfoo said "if" was faster.

I mean really... 7 hundredths of a second change for 10 million loops? That's not faster or slower, statistically.... that's equal.

Instead of looking at miniscule timings like this, learn about code refactoring and Big O() notation... how to reduce the number of loops in your code... and most of all, how to use code profilers to see where the real bottlenecks are. Don't worry about the statistically insignificant stuff. ;)

DGM
+3  A: 

How many tests did you do before you averaged? Very, very small deviations are statistically insignificant! There are plenty of reasons for speed to vary slightly between tests.

William Keller
+17  A: 

Some comments about the deparse below:

First, don't use B::Terse, it's obsolete. B::Concise gives you much better information once you are used to it.

Second, you've run it using the literal code given, so condition was taken as a bareword that happens to be true, so the boolean check was optimized away in both cases, which kind of defeats the purpose.

Third, there isn't an extra opcode - the "null" indicates an opcode that's been optimized away (completely out of the execution tree, though still in the parse tree.)

Here's the Concise execution tree for the two cases, which shows them as identical:

$ perl -MO=Concise,-exec -e'($condition) and do { do something }'
1  <0> enter 
2  <;> nextstate(main 2 -e:1) v
3  <#> gvsv[*condition] s
4  <|> and(other->5) vK/1
5      <$> const[PV "something"] s/BARE
6      <1> dofile vK/1
7  <@> leave[1 ref] vKP/REFC
-e syntax OK
$ perl -MO=Concise,-exec -e'if ($condition) { do something }'
1  <0> enter 
2  <;> nextstate(main 3 -e:1) v
3  <#> gvsv[*condition] s
4  <|> and(other->5) vK/1
5      <$> const[PV "something"] s/BARE
6      <1> dofile vK/1
7  <@> leave[1 ref] vKP/REFC
-e syntax OK
ysth
Good points, I'll use Concise from now on.
Leon Timmermans
A: 

It also could depend on the version of Perl. Which you haven't mentioned. And the difference is not enough to worry about anyway. So use whatever makes more sense.

runrig