The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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.