哪个表现更好 - 在perl中使用grep vs for循环?

vp8*_*vp8 0 arrays perl performance

假设用户想要根据特定条件从数组中过滤元素.用户有两种选择.要么他可以使用一行grep语句,要么写一个for循环并根据特定条件存储元素.

例如

my @array = (1, 2, 3, 4, 5, 6, 7, 8);

选项1 : my @filtered = grep { $_/2 eq 0 } @array;

选项2:

foreach (@array) 
{ 
  if($_/2 eq 0) { 
    push @filtered, $_;
  } 
}
Run Code Online (Sandbox Code Playgroud)

如果性能是一个因素,哪种是首选的写作方式?

zdi*_*dim 6

由于grep具有特定的优化,因此第一种选择通常必须更快.

但是,该陈述过于笼统,您需要对其进行基准测试,特别是在适用于您的工作的条件下.

使用Benchmark模块的示例

use warnings;
use strict;
use feature 'say';    
use Getopt::Long;
use Benchmark qw(cmpthese);

my $time = 3;
my $size = 10_000;

GetOptions( 'time=i' => \$time, 'size=i' => \$size )  or usage();

sub w_grep {
    my @res = grep { $_/2 > $size/4 } @{$_[0]};
    return \@res;
}

sub w_for {
    my @res;
    for (@{$_[0]}) { 
        push @res, $_ if $_/2 > $size/4; 
    }   
    return \@res;
}

my @t = 1..$size;

cmpthese( -$time, {
    grep => sub { w_grep(\@t) },
    for  => sub { w_for(\@t) },
});

sub usage {
    say STDERR "Usage: $0 [--time NUM] [--size NUM]";
    exit;
}
Run Code Online (Sandbox Code Playgroud)

大约一半时间条件都是正确的,因此标量会被创建并经常添加.创建大量标量是昂贵的,这可能是主要因素,您的条件是多么频繁.

它打印(在CentOS 7下的v5.16桌面上)

       Rate  for grep
for   948/s   -- -13%
grep 1085/s  14%   --

但是,如果我们让条件更具限制性$_/2 > $size/2,那么我们就得到了

       Rate  for grep
for  1217/s   --  -6%
grep 1296/s   6%   --

而当它大部分时间成功时,比如说$_/2 > 10,费率是

       Rate  for grep
for   945/s   -- -28%
grep 1304/s  38%   --

这表明for随着阵列的增加,进一步落后.

但是请记住,这取决于你在测试中做出的选择的许多其他方式,一些相当微妙,一些不那么微妙.

例如,首先解压缩arrayref(my @ary = @{ $_[0] };)会将差异减少到几个百分点,因为运行时主要是创建本地数组.这会引发你的测试 - 或者反映你的情况.您需要仔细选择您的条件.

当然,数量也随阵列大小,计算的复杂性等而变化.