in reply to RFC: Text::Grap

In simple cases there is NO performance gain in using your function or even XS-based first() of List::Util :)
grep in scalar context is much faster :)

UPD: Tanktalus found a bug in my benchmark, so i corrected it :) The first function from List::Util beats the grep-based solution if the "good" element appears in the first middle of the array.

Have a look at the benchmark:

#!/usr/bin/perl use warnings; use strict; use List::Util 'first'; use Benchmark qw(:hireswallclock cmpthese); sub grap (&@) { my ($sub,@list) = @_; foreach (@list) { return 1 if ($sub->($_)); } return; } my $count = 10000; our ($start, $end, $middle); $_ = [(0) x $count] foreach ($start, $end, $middle); $start->[0] = 1; $middle->[($count/2) -1] = 1; $end->[$count-1] = 1; foreach my $name (qw/start middle end/) { print uc "\n$name:\n"; cmpthese ( -1,{ 'grap' => 'my $result = grap { $_ } @$'.$name, 'grep' => 'my $result = grep { $_ } @$'.$name, 'first'=> 'my $result = first { $_ } @$'.$name, }) }
And at its result (the uppercase words denote the position of the searched element in the array):
START: Rate grap grep first grap 638/s -- -14% -99% grep 746/s 17% -- -99% first 57971/s 8983% 7672% -- MIDDLE: Rate grap first grep grap 175/s -- -76% -77% first 735/s 319% -- -3% grep 758/s 332% 3% -- END: Rate grap first grep grap 102/s -- -73% -86% first 377/s 269% -- -50% grep 751/s 635% 99% --

Replies are listed 'Best First'.
Re^2: RFC: Text::Grap
by Tanktalus (Canon) on Jul 13, 2006 at 14:04 UTC

    I'm not really convinced you're testing what you think you're testing. That's because you're attempting to close on the lexical start/middle/end variables, but the string is being eval'd way outside of that scope. That's why, when possible, I prefer to see anonymous code refs instead. So I tried converting your code to that - and, while I was at it, I made a minor optimisation to grap where I didn't copy all the elements to a lexical variable first ("grap2"). And then another minor optimisation to stop copying anything ("grap3").

    And the results are much different from yours:
    START: Rate grap grep grap2 grap3 first grap 3397/s -- -37% -93% -93% -99% grep 5381/s 58% -- -89% -89% -99% grap2 47287/s 1292% 779% -- -3% -92% grap3 48596/s 1330% 803% 3% -- -92% first 580886/s 16998% 10695% 1128% 1095% -- MIDDLE: Rate grap grap3 grap2 first grep grap 1152/s -- -22% -23% -75% -79% grap3 1486/s 29% -- -0% -67% -72% grap2 1493/s 30% 0% -- -67% -72% first 4567/s 297% 207% 206% -- -15% grep 5381/s 367% 262% 260% 18% -- END: Rate grap grap3 grap2 first grep grap 756/s -- -15% -16% -69% -86% grap3 891/s 18% -- -1% -63% -84% grap2 898/s 19% 1% -- -63% -84% first 2400/s 218% 170% 167% -- -56% grep 5493/s 627% 517% 512% 129% --
    Which tells me that the second optimisation I made (grap3 vs grap2) isn't much of one ;-)

    However, these are much lower numbers for rates which tells me that they are looping each time. I have a really fast machine already - I don't see how you could loop through 10,000 elements via grep, and do that 2.3 million times per second - that's 23 billion function calls per second, way past believability in any language on a single CPU.

      I just realised that we both did not include in the benchmark the solution that beats first() in all cases—an inlined foreach loop :)

      Benchmark code:

      Results on my machine:

      START: Rate grap grep grap2 grap3 first foreach grap 605/s -- -19% -93% -93% -99% -100% grep 745/s 23% -- -91% -91% -99% -100% grap2 8416/s 1291% 1030% -- -2% -84% -99% grap3 8566/s 1316% 1050% 2% -- -84% -99% first 53924/s 8811% 7140% 541% 530% -- -95% foreach 1005403/s 166050% 134888% 11846% 11637% 1764% -- MIDDLE: Rate grap grap2 grap3 first grep foreach grap 169/s -- -31% -32% -77% -78% -84% grap2 244/s 45% -- -2% -67% -68% -77% grap3 249/s 47% 2% -- -67% -68% -76% first 746/s 342% 205% 200% -- -3% -29% grep 772/s 358% 216% 210% 3% -- -27% foreach 1056/s 526% 332% 325% 42% 37% -- END: Rate grap grap3 grap2 first foreach grep grap 99.3/s -- -18% -20% -73% -81% -86% grap3 121/s 22% -- -3% -68% -77% -84% grap2 124/s 25% 3% -- -67% -76% -83% first 372/s 275% 208% 199% -- -29% -49% foreach 526/s 430% 335% 323% 41% -- -28% grep 735/s 640% 508% 491% 98% 40% --
      Thank you :) I was surprised by the results of the benchmark as they were countrary to the common sense :), but could not figure out the bug :) All i needed was to replace my with our :) I'll update my benchmark.