Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

This is an observation for the public record, more than it is a question. The speed of returning pointers to arrays in 5.10.0 is much faster than the speed of returning arrays:
#!/usr/bin/perl -w use strict; my $arraylength=1000; sub return_arrays { my @array; for (my $i=0; $i<$arraylength; ++$i) { push(@array, rand()); } return @array; ## or return \@array; } my $now=time(); my $sum=0; for (my $j=0; $j<100_000; ++$j) { my @v= return_arrays(); ## or my $v= $sum+= $v[ rand($arraylength) ]; ## of $v->[ } print "$sum\n"; print "Time: ".(time()-$now)." seconds\n";
on a Mac Pro, the array version takes 63 seconds. the reference version takes 22 seconds.

my guess is that perl actually copies the array on a return, rather than just move pointers around. this seems somewhat inefficient.

Replies are listed 'Best First'.
Re: Speed of Array Returns
by moritz (Cardinal) on Jan 30, 2010 at 23:06 UTC

    Note that a subroutine doesn't return an array, but rather a list. That can make a lot of difference. Consider this code:

    use 5.010; { my @a = (1, 2, 3); sub a { return @a; } } my @x = a(); push @x, 4; say a();
    If perl returned by reference (as you seem to suggest), this would print 1234, now it prints 123.

    You can't have everything and a pony...

    Perl 6 - links to (nearly) everything that is Perl 6.
Re: Speed of Array Returns
by jethro (Monsignor) on Jan 30, 2010 at 23:36 UTC

    Ideally you would have the choice, and perl as it happens offers this choice.

    Most of the time you want a copy (on the way in and on the way out of a subroutine), because it decouples the subroutine: You can just assume that your parameters are unchanged by a subroutine and that you can change the result of a subroutine without having to think about any side effects if you further process that result (moritz gave a simple example of these side effects).

    Think about the last 10 subroutines you wrote. If you changed all these subroutines to return pointers to arrays instead of arrays (or vice versa) would you notice any speed difference? Probably not. And even if you did, could you have the same difference by only speeding up one of these 10? Probably. So is it faster to find that one subroutine to speed up or is it faster to think of how to avoid any side effects any time you write a call to a subroutine and find the bugs afterwards if you make a single mistake there

Re: Speed of Array Returns
by iaw4 (Monk) on Jan 30, 2010 at 23:11 UTC
    ironically, the speed of passing arguments into functions is unaffected.
    #!/usr/bin/perl -w use strict; my $arraylength=1000; open(FOUT,">", "/dev/null"); my $now=time(); for (my $j=0; $j<100_000; ++$j) { # create a 1000 array my @array; for (my $i=0; $i<$arraylength; ++$i) { push(@array, rand()); } passed_array(\@array); sub passed_array { print FOUT $_[0]->[rand($arraylength)]; } } print "Time: ".(time()-$now)." seconds\n"; close(FOUT);
    this takes about 38 seconds, regardless of whether the array is passed by reference or by itself.

      That's a bad benchmark then. Flattening a thousand-element array into subroutine parameters requires putting a thousand SVs on the Perl 5 stack. Passing the same array by reference requires putting a single RV on the Perl 5 stack. Which one do you think will take longer?

        Agree with chromatic. I tried following:
        use Benchmark qw(cmpthese); my @array = (1..1000); cmpthese(-2, { call => sub { foo(@array); }, call_ref => sub { foo(\@array); }, }); sub foo { }
        and got that call with reference is much faster:
        Rate call call_ref call 168822/s -- -93% call_ref 2575003/s 1425% --
        -- Roman
        actually, perl seemed smart enough to recognize that if it sees a call with an array, it can pass the array as a pointer. when I tried it, call(@longarray) and call(\@longarray) took almost the same amount of time. so, I do not believe perl literally puts all 1,000 elements of longarray on the stack and then pops it, as C would do.

        the mystery to me was why perl was not smart enough to do the same when I do return @longarray.

        apparently, this has to do with arrays vs. lists. I do understand now that the two are different. alas, I do not understand what the purpose of a list is. it doesn't seem to make things faster, and is more restrictive. besides, the difference is confusing. if sub's returned arrays, then they could easily be assigned back to arrays, no matter how long.

        thanks everyone, though.

Re: Speed of Array Returns
by ikegami (Patriarch) on Jan 31, 2010 at 17:12 UTC

    Just like the only thing you can pass to a sub is a list of scalars, the only thing you can return from a sub is a list of scalars.

    You are evaluating an array in list context. An array in list context returns a list of its elements.

Re: Speed of Array Returns
by Anonymous Monk on Jan 30, 2010 at 23:33 UTC
    FWIW (after a few runs, this seems representative; too impatient to do higher iterations):
    #!/usr/bin/perl use strict; use warnings; use Benchmark ":all"; my $len = 1_000; sub returnlist { my @rray = map({rand()} (1..$len)); return( @rray); } sub returnref { my @rray = map({rand()} (1..$len)); return(\@rray); } cmpthese(10_000, { "returnlist" => sub { my @foo = returnlist(); }, "returnref" => sub { my ($foo) = returnref(); }, }); __END__ Rate returnlist returnref returnlist 633/s -- -24% returnref 829/s 31% --

    # perl -v
    This is perl, v5.10.1 (*) built for i686-cygwin-thread-multi-64int
    (Cygwin 1.7 on 32bit XP)