Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

schwern (1528)

schwern
  (email not shown publicly)
http://schwern.net/
AOL IM: MichaelSchwern (Add Buddy, Send Message)
Jabber: schwern@gmail.com

Schwern can destroy CPAN at his whim.

Journal of schwern (1528)

Saturday December 22, 2007
10:12 AM

Smart match beats the hell out of grep() and first()

[ #35186 ]

Alberto Simões posted up an interesting benchmark illustrating that ~~, the new smart match operator in 5.10, outperforms both grep and List::Util::first() in the "is X in this list" role.

Here's my results:

$ perl5.10.0 bench.plx
Benchmark: timing 100000 iterations of first, grep BLOCK, grep EXPR, ~~...
     first: 23 wallclock secs (22.78 usr +  0.03 sys = 22.81 CPU) @ 4384.04/s (n=100000)
grep BLOCK: 18 wallclock secs (18.48 usr +  0.03 sys = 18.51 CPU) @ 5402.49/s (n=100000)
  grep EXPR: 17 wallclock secs (17.56 usr +  0.03 sys = 17.59 CPU) @ 5685.05/s (n=100000)
        ~~: 10 wallclock secs ( 9.97 usr +  0.01 sys =  9.98 CPU) @ 10020.04/s (n=100000)

What I believe it's illustrating is the Perl optimization rule of thumb that the more work you let the opcodes do, the better. ~~ doesn't have to execute a Perl expression over and over again, it can do that in optimized C.

Here's the benchmark code:

use Benchmark;
use 5.010;
use List::Util qw(first);
 
my @array = map { chr(64+int(rand(26)))."$_" } 1..1000;
my $result;
my $needle;
 
timethese(100_000, {
           'first'   => sub {
               $needle = chr(64+int(rand(26))).int(rand(1000)+1);
               $result = first { $_ eq $needle } @array;
           },
           'grep BLOCK'   => sub {
               $needle = chr(64+int(rand(26))).int(rand(1000)+1);
               $result = grep { $_ eq $needle } @array;
           },
           'grep EXPR'   => sub {
               $needle = chr(64+int(rand(26))).int(rand(1000)+1);
               $result = grep $_ eq $needle, @array;
           },
           '~~' => sub {
               $needle = chr(64+int(rand(26))).int(rand(1000)+1);
               $result = $needle ~~ @array;
           }
});

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • As a result of this post, I updated the tutorial I wrote on getting matching items from arrays

    http://perlmonks.org/?node_id=371938 [perlmonks.org]
  • Wouldn't it be a more realistic test if you used the return value from first/grep/~~? Is grep one of the builtins that's optimized for void context? I can never remember...
    • Good point. I've updated the benchmark to work in scalar context. Results are similar. grep isn't optimized in void context because there's no valid use for it, the whole point is the return value. Then again the same could be said of smart match. I guess we need a "smart match in void context" warning.