in reply to Loops and speed

Time for the trusty old Benchmark.pm
But first check with B::Deparse
print "Hey" if $responce eq "hi"; # is optimised/parsed to: (($responce eq "hi") and print("Hey"));
So our favourite construct doesn't do what we think it will....

I couldn't get a definate answer out of Benchmark, but generally the fastest method is:
if ($responce eq "hi") { print "Hey" }
But the others aren't far behind

print "Hey" if $responce eq "hi"; (($responce eq "hi") and print("Hey");
You would expect the second one of those to be faster if anything since that is what the first one is changed to, but maybe my tests were screwy.

Tests run on linux 5.005_03

Update: Okay I had another look at my Deparse results in relation to Adam's reply below. I generally use perl -MO=Deparse,-p -e ... since it adds extra bracketing and things so I can tell exactly how things are working in terms of precedence and stuff. It seems that using -p rearranges the foo if blah; to blah and foo but without -p, Deparse leaves it alone. So my question is, which result is more correct, does perl do the full transformation like Deparse,-p or does it just do the equivilent to plain Deparse before the next stage of complimation?

Here's where my benchmarks came from:

my @foo = map {int rand 3} 1..1000; timethese(-15, { one => 'for (@foo) { print "$_\n" if $_; }', two => 'for (@foo) { if ($_) {print "$_\n";} }', three => 'for (@foo) { ($_ and print("\n")); }', } ); __END__ Result: one: 15 wallclock secs (14.99 usr + 0.01 sys = 15.00 CPU) @ 9421.60 +/s (n=141324) two: 16 wallclock secs (15.01 usr + -0.01 sys = 15.00 CPU) @ 9217.53 +/s (n=138263) three: 14 wallclock secs (15.43 usr + 0.01 sys = 15.44 CPU) @ 8842.75 +/s (n=136532) another run one: 6 wallclock secs ( 7.00 usr + 0.01 sys = 7.01 CPU) @ 9369.33 +/s (n=65679) three: 7 wallclock secs ( 7.57 usr + 0.00 sys = 7.57 CPU) @ 9237.78 +/s (n=69930) two: 7 wallclock secs ( 7.44 usr + 0.00 sys = 7.44 CPU) @ 8758.33 +/s (n=65162) and another two: 9 wallclock secs ( 7.00 usr + 0.00 sys = 7.00 CPU) @ 9757.14 +/s (n=68300) one: 6 wallclock secs ( 7.00 usr + 0.01 sys = 7.01 CPU) @ 9133.24 +/s (n=64024) three: 5 wallclock secs ( 7.06 usr + 0.00 sys = 7.06 CPU) @ 8828.47 +/s (n=62329)
Like I said it wasn't totally constant, so what did I do wrong in creating those benchmarks?

Replies are listed 'Best First'.
Re: Re: Loops and speed
by chipmunk (Parson) on Dec 17, 2000 at 22:40 UTC
    This Benchmark exhibits some of the same problems I discussed in Re: Re: Craftier. In particular, @foo is a lexical variable which is not accessible in the Benchmark package, where your code snippets are being compiled. All of your snippets are working on an empty @foo. (You might have noticed that, despite the three print statements, your code never actually printed anything.)

    Since you're passing quoted strings, all you're really testing is the time to compile each snippet, which is not a very useful measure. Also note that the third snippet omitted $_ in the print statement.

    Here's an improved benchmark.

    #!/usr/local/bin/perl -w use strict; use Benchmark; my @foo = map {int rand 3} 1..100; open(OUT, ">bm.out") or die "$!\n"; # Note: bm.out will be a large file when this is done. :) timethese(-10, { mod => sub { for (@foo) { print OUT "$_" if $_; } print OUT "\n"; }, block => sub { for (@foo) { if ($_) { print OUT "$_"; } } print OUT "\n"; }, and => sub { for (@foo) { $_ and print OUT "$_"; } print OUT "\n"; }, } ); __END__ Benchmark: running and, block, mod, each for at least 10 CPU seconds.. +. and: 3554.42/s block: 3530.86/s mod: 3511.90/s
    With a re-structured benchmark, all three options are roughly equivalent, as you would expect.

    However, there's also a lot of extra code in each snippet, which could be obscuring actual differences between the code we're really trying to test. In particular, I'd expect the print to be slow relative to the rest of the code.

    Here's another benchmark.

    #!/usr/local/bin/perl -w use strict; use Benchmark; my $foo = 0; # $foo will be toggled between true and false my $x; timethese(-10, { mod => sub { $x = 1 if $foo ^= 1 }, block => sub { if ($foo ^= 1) { $x = 1 } }, and => sub { $foo ^= 1 and $x = 1 }, } ); __END__ Benchmark: running and, block, mod, each for at least 10 CPU seconds.. +. and: 233020.67/s block: 230307.69/s mod: 234463.20/s Benchmark: running and, block, mod, each for at least 10 CPU seconds.. +. and: 237002.40/s block: 236647.46/s mod: 226841.12/s
    This benchmark also shows no significant difference between the three forms.

    We can draw two conclusions from these results: first, that it is important to have a well-constructed benchmark; and second, that the three forms of if/then are equivalent in terms of efficiency.