From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

NAME

List::Gen::Benchmark - performance tips for using List::Gen

SYNOPSIS

this document contains various benchmarks comparing the parallel syntax styles that List::Gen provides.

running the benchmark

perl -MList::Gen::Benchmark

benchmark tests

iteration:
reduce: my $x = $gen->reduce(sub {$a + $b});
# same as $gen->sum
do: my $x; $gen->do(sub {$x += $_})
for: my $x; $x += $_ for @$gen;
more/next: my $x; $gen->reset;
$x += $gen->next while $gen->more;
$gen->(): my ($x, $n); $gen->reset;
$x += $n while ($n) = $gen->();
iterator: my $it = $gen->iterator;
my ($x, $n); $gen->reset;
$x += $n while ($n) = $it->();
next: my ($x, $n); $gen->reset;
$x += $n while ($n) = $gen->next;
handle: my $x; local $_; $gen->reset;
$x += $_ while <$gen>;

benchmark results

iteration:
[+] 0 .. 10:
Rate reduce do for more/next $gen->() iterator next handle
reduce 28489/s -- -8% -30% -55% -55% -67% -68% -71%
do 31109/s 9% -- -24% -51% -51% -64% -65% -69%
for 40877/s 43% 31% -- -35% -35% -53% -55% -59%
more/next 62977/s 121% 102% 54% -- -0% -27% -30% -36%
$gen->() 63141/s 122% 103% 54% 0% -- -27% -30% -36%
iterator 86340/s 203% 178% 111% 37% 37% -- -4% -13%
next 90021/s 216% 189% 120% 43% 43% 4% -- -9%
handle 98964/s 247% 218% 142% 57% 57% 15% 10% --
[+] 0 .. 50:
Rate for $gen->() more/next reduce do next iterator handle
for 8762/s -- -40% -40% -41% -43% -59% -60% -63%
$gen->() 14546/s 66% -- -1% -2% -5% -31% -34% -38%
more/next 14646/s 67% 1% -- -2% -4% -31% -33% -38%
reduce 14892/s 70% 2% 2% -- -3% -30% -32% -37%
do 15278/s 74% 5% 4% 3% -- -28% -30% -35%
next 21222/s 142% 46% 45% 43% 39% -- -3% -10%
iterator 21892/s 150% 51% 49% 47% 43% 3% -- -7%
handle 23454/s 168% 61% 60% 57% 54% 11% 7% --
[+] 0 .. 100:
Rate for more/next $gen->() reduce do next iterator handle
for 4424/s -- -40% -42% -53% -53% -60% -61% -64%
more/next 7385/s 67% -- -3% -21% -21% -34% -34% -39%
$gen->() 7607/s 72% 3% -- -19% -19% -32% -32% -38%
reduce 9340/s 111% 26% 23% -- -0% -16% -17% -23%
do 9341/s 111% 26% 23% 0% -- -16% -17% -23%
next 11108/s 151% 50% 46% 19% 19% -- -1% -9%
iterator 11253/s 154% 52% 48% 20% 20% 1% -- -8%
handle 12190/s 176% 65% 60% 31% 31% 10% 8% --
[+] 0 .. 1000:
Rate for more/next $gen->() next iterator do reduce handle
for 446/s -- -39% -42% -61% -62% -62% -63% -64%
more/next 735/s 65% -- -4% -35% -37% -37% -39% -41%
$gen->() 763/s 71% 4% -- -33% -34% -34% -37% -38%
next 1131/s 153% 54% 48% -- -3% -3% -7% -9%
iterator 1164/s 161% 58% 52% 3% -- -0% -4% -6%
do 1165/s 161% 58% 53% 3% 0% -- -4% -6%
reduce 1210/s 171% 65% 58% 7% 4% 4% -- -2%
handle 1237/s 177% 68% 62% 9% 6% 6% 2% --
[+] 0 .. 10000:
Rate for more/next $gen->() next iterator do handle reduce
for 44.5/s -- -40% -42% -60% -62% -63% -64% -64%
more/next 74.0/s 66% -- -3% -34% -36% -39% -41% -41%
$gen->() 76.6/s 72% 4% -- -32% -34% -37% -38% -39%
next 113/s 153% 52% 47% -- -3% -8% -9% -10%
iterator 116/s 161% 57% 52% 3% -- -5% -7% -7%
do 122/s 174% 65% 59% 8% 5% -- -2% -3%
handle 124/s 179% 68% 62% 10% 7% 2% -- -1%
reduce 125/s 182% 70% 64% 11% 8% 3% 1% --
[+] 0 .. 100000:
Rate for more/next $gen->() next iterator reduce do handle
for 4.47/s -- -41% -42% -61% -62% -63% -64% -64%
more/next 7.55/s 69% -- -2% -34% -36% -38% -39% -40%
$gen->() 7.71/s 72% 2% -- -32% -35% -36% -38% -39%
next 11.4/s 155% 51% 48% -- -4% -6% -8% -9%
iterator 11.9/s 166% 57% 54% 4% -- -2% -4% -5%
reduce 12.1/s 170% 60% 57% 6% 2% -- -2% -4%
do 12.3/s 176% 64% 60% 8% 4% 2% -- -2%
handle 12.5/s 180% 66% 63% 10% 6% 4% 2% --

interpretation

once the generator size gets large enough to mask differences in initialization code, the access methods fall into 4 classes.

1: for

while it is one of the most perlish ways to write the loop, the $x += $_ for @$gen construct uses a tied array, and unfortunately ties are fairly slow. all of the other constructs use the exact same underlying FETCH and FETCHSIZE methods that the tied array uses, yet they are all much faster.

2: more/next, $gen->()

these are almost the same speed, and are the slowest of the non-tied access methods. the more/next pair results in unneeded function calls, since next is checking the more condition already. the overloaded dereference has some interpreter overhead.

3: next, iterator, reduce, do

these are the faster ways to access generators, the ranking of which depends on the size of the generator. next and iterator are almost the same, and are fast across the size range. iterator will always be slightly faster than next since it is the function used internally by next

reduce and do both have slower start-up time than next or iterator due to a bit of initialization code. this initialization code allows for their loops to be optimized further, which lets reduce and do achieve higher speeds for larger generators.

4: handle

handle iteration in a while loop is heavily optimized by perl, and is subsequently one of the fastest techniques for iterating over a generator, and this speed is independent of generator size.

in summary, stick to next, iterator, reduce, do, or handle iteration styles if performance is a concern.

AUTHOR

Eric Strom, <asg at cpan.org>

COPYRIGHT & LICENSE

copyright 2009-2011 Eric Strom.

this program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

see http://dev.perl.org/licenses/ for more information.