Perl list interpolation performance

Viewed 150

Background

Perldoc for List::Util suggests that some uses of map may be replaced by reduce in order to avoid creating unnecessary intermadiate list:

For example, to find the total length of the all the strings in a list, we could use

$total = sum map { length } @strings;

However, this produces a list of temporary integer values as long as the original list of strings, only to reduce it down to a single value again. We can compute the same result more efficiently by using reduce with a code block that accumulates lengths by writing this instead as:

$total = reduce { $a + length $b } 0, @strings;

That makes sense. However, reduce in order to work in this example needs "identity value", that would be prepended to input list:

$total = reduce { $a + length $b } 0, @strings;
#                                  ^^^^^^^^^^^

That makes me think, doesn't 0, @strings create a new list, thus offset any gains from not creaing list in map?

Question

How does list interpolation ($scalar, @list) work in Perl? Does it involve copying elements from source list or is it done in some smarter way? My simple benchmark suggests copying taking place:

use strict;
use warnings;
use Benchmark qw/cmpthese/;

my @a1 = 1..10;
my @a2 = 1..100;
my @a3 = 1..1000;
my @a4 = 1..10000;
my @a5 = 1..100000;
my @a6 = 1..1000000;

cmpthese(10000, {
    'a1' => sub { my @l = (0, @a1); },
    'a2' => sub { my @l = (0, @a2); },
    'a3' => sub { my @l = (0, @a3); },
    'a4' => sub { my @l = (0, @a4); },
    'a5' => sub { my @l = (0, @a5); },
    'a6' => sub { my @l = (0, @a6); },
});

Results:

            (warning: too few iterations for a reliable count)
        Rate       a6       a5       a4       a3       a2       a1
a6    17.6/s       --     -90%     -99%    -100%    -100%    -100%
a5     185/s     952%       --     -90%     -99%    -100%    -100%
a4    1855/s   10438%     902%       --     -90%     -99%    -100%
a3   17857/s  101332%    9545%     862%       --     -91%     -98%
a2  200000/s 1135940%  107920%   10680%    1020%       --     -80%
a1 1000000/s 5680100%  540000%   53800%    5500%     400%       --

Bonus question: If my assumptions are correct (i.e. 0, @strings creates a new list), does replacing map with reduce make sense?

3 Answers
Related