在Perl的foreach中,$ _比命名变量更有效吗?

man*_*del 8 variables perl performance loops

我是Perl的新手,我想知道以下哪个循环更有效:

my @numbers = (1,3,5,7,9);
foreach my $current (@numbers){
    print "$current\n";
}
Run Code Online (Sandbox Code Playgroud)

要么

my @numbers = (1,3,5,7,9);
foreach (@numbers){
    print "$_\n";
}
Run Code Online (Sandbox Code Playgroud)

我想知道这一点,以便知道$ _的使用是否更有效,因为它是放在寄存器中,因为它是常用或不常用的.我已经编写了一些代码,我正在尝试清理它,并且我发现我使用的第一个循环比第二个循环更频繁.

tdd*_*key 14

您是否已经确定在使用这些循环的代码部分中存在性能问题?如果没有,您希望选择更具可读性且更易于维护的那个.速度的任何差异都可能是微不足道的,特别是与系统的其他部分相比.始终首先编码可维护性,然后编写配置文件,然后编写性能代码

"过早优化是所有邪恶的根源"[1]

[1] Knuth,唐纳德.结构化编程,参见陈述,ACM Journal Computing Surveys,Vol 6,No.4,1974年12月.p.268.

  • 此外,这不是问题.OP没有问_他应该优化?他只是问哪个更快. (3认同)

Hyn*_*dil 11

甚至知道过早优化是所有邪恶的根源

{
  local $\ = "\n";
  print foreach @numbers;
}
Run Code Online (Sandbox Code Playgroud)

但有些期望可能是错误的.测试有点奇怪,因为输出会产生一些奇怪的副作用,顺序可能很重要.

#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw(:all :hireswallclock);

use constant Numbers => 10000;

my @numbers = (1 .. Numbers);

sub no_out (&) {
    local *STDOUT;
    open STDOUT, '>', '/dev/null';
    my $result  = shift()->();
    close STDOUT;
    return $result;
};

my %tests = (
    loop1 => sub {
        foreach my $current (@numbers) {
            print "$current\n";
        }
    },
    loop2 => sub {
        foreach (@numbers) {
            print "$_\n";
        }

    },
    loop3 => sub {
        local $\ = "\n";
        print foreach @numbers;
        }
);

sub permutations {
    return [
        map {
            my $a = $_;
            my @f = grep {$a ne $_} @_;
            map { [$a, @$_] } @{ permutations( @f ) }
            } @_
        ]
        if @_;
    return [[]];
}

foreach my $p ( @{ permutations( keys %tests ) } ) {
    my $result = {
        map {
            $_ => no_out { sleep 1; countit( 2, $tests{$_} ) }
            } @$p
    };

    cmpthese($result);
}
Run Code Online (Sandbox Code Playgroud)

可以预期loop2应该比loop1更快

       Rate loop2 loop1 loop3
loop2 322/s    --   -2%  -34%
loop1 328/s    2%    --  -33%
loop3 486/s   51%   48%    --
       Rate loop2 loop1 loop3
loop2 322/s    --   -0%  -34%
loop1 323/s    0%    --  -34%
loop3 486/s   51%   50%    --
       Rate loop2 loop1 loop3
loop2 323/s    --   -0%  -33%
loop1 324/s    0%    --  -33%
loop3 484/s   50%   49%    --
       Rate loop2 loop1 loop3
loop2 317/s    --   -3%  -35%
loop1 328/s    3%    --  -33%
loop3 488/s   54%   49%    --
       Rate loop2 loop1 loop3
loop2 323/s    --   -2%  -34%
loop1 329/s    2%    --  -33%
loop3 489/s   51%   49%    --
       Rate loop2 loop1 loop3
loop2 325/s    --   -1%  -33%
loop1 329/s    1%    --  -32%
loop3 488/s   50%   48%    --
Run Code Online (Sandbox Code Playgroud)

有时我观察到loop1比一般快15%-20%loop2我但我无法确定原因.

我观察到为loop1和loop2生成了字节码,并且在创建my变量时只有一个区别.该变量内部未被分配也未被复制,因此该操作非常便宜.差异来自我认为只有"$_\n"不便宜的构造.这些循环应该非常相似

for (@numbers) {
  ...
}

for my $a (@numbers) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

但这个循环更昂贵

for (@numbers) {
  my $a = $_;
  ...
}
Run Code Online (Sandbox Code Playgroud)

并且

print "$a\n";
Run Code Online (Sandbox Code Playgroud)

比...更贵

print $a, "\n";
Run Code Online (Sandbox Code Playgroud)


sch*_*der 6

您可以查看本教程,还可以使用"Benchmark Your Code"这一章来比较这两种方式.


drb*_*rby 6

基准测试:

use Benchmark qw(timethese cmpthese);

my $iterations = 500000;     

cmpthese( $iterations,
  {
    'Loop 1' => 'my @numbers = (1,3,5,7,9);
    foreach my $current (@numbers)
    {
      print "$current\n";
    }', 

    'Loop 2' => 'my @numbers = (1,3,5,7,9);
    foreach (@numbers)
    {
      print "$_\n";
    }'
  }
);
Run Code Online (Sandbox Code Playgroud)

输出:

         Rate     Loop 2 Loop 1
Loop 2  23375/s     --    -1%
Loop 1  23546/s     1%     --
Run Code Online (Sandbox Code Playgroud)

我运行了几次,结果各不相同.我认为可以说没有太大区别.