in reply to Re: Battle Royal Grep vs For
in thread Battle Royal Grep vs For

Just thought I'd muddy the waters a bit more, for fun:

cmpthese -2, { for_0 => sub { for_loop( \@match_0 ) }, for_25 => sub { for_loop( \@match_25 ) }, for_50 => sub { for_loop( \@match_50 ) }, for_75 => sub { for_loop( \@match_75 ) }, for_100 => sub { for_loop( \@match_100 ) }, grep_0 => sub { grep_loop( \@match_0 ) }, grep_25 => sub { grep_loop( \@match_25 ) }, grep_50 => sub { grep_loop( \@match_50 ) }, grep_75 => sub { grep_loop( \@match_75 ) }, grep_100 => sub { grep_loop( \@match_100 ) }, fastgrep_0 => sub { fastgrep_loop( \@match_0 ) }, fastgrep_25 => sub { fastgrep_loop( \@match_25 ) }, fastgrep_50 => sub { fastgrep_loop( \@match_50 ) }, fastgrep_75 => sub { fastgrep_loop( \@match_75 ) }, fastgrep_100 => sub { fastgrep_loop( \@match_100 ) }, noretfor_0 => sub { noretfor_loop( \@match_0 ) }, noretfor_25 => sub { noretfor_loop( \@match_25 ) }, noretfor_50 => sub { noretfor_loop( \@match_50 ) }, noretfor_75 => sub { noretfor_loop( \@match_75 ) }, noretfor_100 => sub { noretfor_loop( \@match_100 ) }, noretgrep_0 => sub { noretgrep_loop( \@match_0 ) }, noretgrep_25 => sub { noretgrep_loop( \@match_25 ) }, noretgrep_50 => sub { noretgrep_loop( \@match_50 ) }, noretgrep_75 => sub { noretgrep_loop( \@match_75 ) }, noretgrep_100 => sub { noretgrep_loop( \@match_100 ) }, }; sub for_loop { my @matches; for ( @{$_[0]} ) { push @matches, $_ if /x/; } return @matches; } sub grep_loop { my @matches = grep /x/, @{$_[0]}; return @matches; } sub fastgrep_loop { return grep /x/, @{$_[0]}; } sub noretfor_loop { for (@{$_[0]}) { $_ =~ /x/ } } sub noretgrep_loop { grep /x/, @{$_[0]}; } __END__ (cropped to fit) Rate grep_100 grep_75 for_100 grep_50 for_75 for_50 gre +p_25 for_25 noretfor_75 grep_100 134/s -- -17% -29% -41% -42% -55% +-62% -68% -79% grep_75 161/s 20% -- -15% -29% -30% -47% +-55% -61% -75% for_100 189/s 41% 17% -- -16% -18% -37% +-47% -55% -71% grep_50 226/s 68% 40% 20% -- -2% -25% +-36% -46% -65% for_75 231/s 72% 43% 22% 2% -- -24% +-35% -45% -64% for_50 302/s 125% 87% 60% 33% 31% -- +-15% -28% -54% grep_25 356/s 165% 121% 88% 57% 54% 18% + -- -15% -45% for_25 419/s 212% 160% 121% 85% 82% 39% + 18% -- -36% noretfor_75 650/s 383% 303% 243% 187% 182% 115% + 82% 55% -- noretfor_100 680/s 406% 321% 259% 200% 195% 125% + 91% 62% 5% noretfor_50 693/s 416% 330% 266% 206% 200% 130% + 95% 66% 7% for_0 693/s 416% 330% 266% 206% 200% 130% + 95% 66% 7% noretfor_0 697/s 419% 332% 269% 208% 202% 131% + 96% 66% 7% noretgrep_50 700/s 421% 334% 270% 209% 204% 132% + 96% 67% 8% noretfor_25 701/s 421% 334% 271% 210% 204% 132% + 97% 67% 8% noretgrep_75 736/s 448% 356% 289% 225% 219% 144% +106% 76% 13% fastgrep_0 740/s 451% 359% 291% 227% 221% 145% +108% 77% 14% fastgrep_75 747/s 456% 363% 295% 230% 224% 147% +110% 78% 15% fastgrep_100 752/s 460% 366% 298% 232% 226% 149% +111% 80% 16% noretgrep_25 769/s 472% 376% 306% 240% 233% 154% +116% 84% 18% noretgrep_0 769/s 472% 377% 307% 240% 233% 155% +116% 84% 18% fastgrep_50 777/s 478% 381% 311% 243% 237% 157% +118% 85% 20% noretgrep_100 781/s 481% 384% 313% 245% 238% 159% +119% 86% 20% grep_0 796/s 492% 393% 321% 252% 245% 164% +123% 90% 23% fastgrep_25 801/s 496% 396% 323% 254% 247% 165% +125% 91% 23%
I skipped "my @values = @{shift()};" in all of them, since this array copy seemed to be a big part of the run time. The point I would take from this is that the performance really depends more on the situation you use them in and how you use them. As kyle says, it's probably best to just use the one that is clearest. For me, that would be fastgrep_loop.
-driver8

Replies are listed 'Best First'.
Re^3: Battle Royal Grep vs For
by kyle (Abbot) on Mar 19, 2008 at 20:37 UTC

    You're right, copying does take time, but I'm not sure that's really what's going on here. I tested some more myself.

    What this is meant to show is really that grep performs differently depending on context.

    Benchmark::cmpthese calls the subs you give it in void context, so if you want another context for your code, you need to provide it. This is part of why the subs I wrote are careful to actually collect (and return) results. That's what these would do in the real world.

    In void context, grep doesn't bother to make a list, so it's a lot faster. It's also faster when I forced a scalar context because it again doesn't make a list. In that case, it just counts the matches and passes out the number. You can see that the void and scalar cases are far ahead of all the others.

    The grep in list context without a copy is only slightly faster than the one that makes a copy. Basically it's in the ballpark of copying while all the others (in void and scalar contexts) are in another ballpark.