Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

Is for(@$array_ref) construct optimized? YES!

by Weasel (Sexton)
on Jun 16, 2002 at 18:16 UTC ( [id://174941] : perlmeditation . print w/replies, xml ) Need Help??

Hello, all!

Many of us know that foreach (@array) {...} is optimized - no extra copying, just some iterations over array. But it was not obvious for me whether or not more complex constructs are optimized this way.
In such cases they better be written as: for ($i=0;$i<=$#array;$i++) {...}

So I wrote simple benchmark program and found out that optimizations which perl performs are quite good:

use strict; use Benchmark; my ($x,$i); my @f = ('a'..'zz'); my $f = \@f; sub first_one { for (@f) {$x++} } sub second_one { for (@$f) {$x++} } sub third_one { for ('a'..'zz') {$x++} } sub fourth_one { for ($i=0;$i<=$#f;$i++) {$x++} } timethese(10_000, { 'first' => \&first_one, 'second' => \&second_one, 'third' => \&third_one, 'fourth' => \&fourth_one, });
Benchmark: timing 10000 iterations of first, fourth, second, third... first: 6 wallclock secs ( 6.02 usr + 0.00 sys = 6.02 CPU) @ 16 +61.68/s (n=10000) fourth: 12 wallclock secs (11.98 usr + 0.00 sys = 11.98 CPU) @ 83 +4.86/s (n=10000) second: 7 wallclock secs ( 6.00 usr + 0.00 sys = 6.00 CPU) @ 16 +67.22/s (n=10000) third: 9 wallclock secs ( 9.57 usr + 0.00 sys = 9.57 CPU) @ 10 +44.50/s (n=10000)
So, I was here to share this knowledge.

Replies are listed 'Best First'.
Re: Is for(@$array_ref) construct optimized? YES!
by Aristotle (Chancellor) on Jun 16, 2002 at 19:38 UTC
    You're preaching to the converted. :) If you use -MO=Deparse, you'll see that the for(;;) gets compiled to a while with a continue block, the latter being where the massive performance difference weighs in. Considering that the for(@array) form eradicates fence post errors from the root, there's rarely any good reason to use for(;;) in Perl.

    Update: I forgot. Depending on your version of B::Deparse you may need increase the exposition level with the -x switch in order to see what things really look like to Perl under the hood.
    $ perl -MO=Deparse,-x7 -e 'for($i=0;$i<=10;$i++){}' $i = 0; while ($i <= 10) { (); } continue { ++$i } -e syntax OK $ perl -MB::Deparse -e' print "$B::Deparse::VERSION\n"' 0.6 $ perl -v This is perl, v5.6.1 built for i386-linux [...]

    Makeshifts last the longest.

      Sorry, I just checked a situation and can not confirm your sayings. Here is my log:
      D:\Work\PerlScripts\utl>perl -MO=Deparse -we "$x=[];for(@$x){}" $x = []; foreach $_ (@$x) { (); } -e syntax OK D:\Work\PerlScripts\utl>perl -MO=Deparse -we "$x=[];for(;;){}" Name "main::x" used only once: possible typo at -e line 1. $x = []; for (;;) { (); } -e syntax OK D:\Work\PerlScripts\utl>perl -MO=Deparse -we "$x=[];for($i=0;$i<=$#x;$ +i++){}" $x = []; for ($i = 0; $i <= $#x; ++$i) { (); } -e syntax OK
      This is probably version-dependent (which perl version you use?) and with less probablilty $^O-dependent (what is $^O in your case?)

      I think we'll find common denominator soon.

      update: after I saw your update I understood more and now I think we found that commond denominator that I've just mentioned. Thanks.

        On Linux with Perl5.6.0:
        $ perl -MO=Deparse -we '$x=[];for($i=0;$i<=$#x;$i++){}'
        $x = [];
        $i = 0;
        while ($i <= $#x) {
        continue {
        -e syntax OK
        Screamer is right - but thanks for preaching anyway, not all of us are 'converted' just yet. ;)


        (the triplet paradiddle with high-hat)