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

schwern on 2007-12-22T15:12:30

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; } });


Thanks - tutorial updated

Limbic Region on 2007-12-22T16:20:25

As a result of this post, I updated the tutorial I wrote on getting matching items from arrays

http://perlmonks.org/?node_id=371938

Void context?

ChrisDolan on 2007-12-23T01:12:14

Wouldn't it be a more realistic test if you used the return value from first/grep/user/~? Is grep one of the builtins that's optimized for void context? I can never remember...

Re:Void context?

schwern on 2007-12-23T10:50:35

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.