1

[Strawberry Perl v5.16.3,Windows 7 x64,通过 cmd 执行,例如 c:\strawberry> perl test.pl 100000]

症状:下面的代码:foreach (1..$ARGV[0]) { foo($_); },执行速度比我在它之前包含这个额外的行时慢大约 20%:my $num = $ARGV[0];

问题:谁能帮我理解为什么?

请注意,在第二种情况下,在我初始化和设置之后$num,我不会$num在循环参数中使用。如果是这种情况,我可能会确信$ARGV[0]在 forloop 中反复测试比我自己定义的变量要慢......但事实并非如此。

为了跟踪时间,我use Time::HiRes; my $time = [Time::HiRes::gettimeofday()];在脚本的顶部使用:,print "\n1: ", Time::HiRes::tv_interval($time);在底部使用:。

使困惑!

谢谢,

迈克尔

编辑

我包含了整个脚本,在违规行之前有一个注释......有趣的是,看起来时间差异至少部分取决于我的冗余初始化%h,以及@chain......这变得很奇怪。

    use Time::HiRes; my $time = [Time::HiRes::gettimeofday()];

    #my $max=$ARGV[0];
    my %h = (1=>1,89=>89);
    $h{1}=1;
    $h{89}=89;
    my @chain=();
    my $ans=0;

    sub sum{my $o=0; foreach (@_){$o+=$_}; return $o;}

    foreach (1..$ARGV[0]-1){
        my $x=$_;
        my @chain = ();
        while(!exists($h{$x})){
            push(@chain,$x);
            $x = sum(map {$_**2} split('',$x));
        }
        foreach (@chain){$h{$_}=$h{$x} if !exists($h{$_});}
    }

    print "\n1: ", Time::HiRes::tv_interval($time);
    foreach (1..$ARGV[0]){$ans++ if ($h{$_}==89);}
    print "\n2: ", Time::HiRes::tv_interval($time);
4

1 回答 1

2

在我的系统上(GNU/Linux 上的 perl 5.16.3)没有可测量的差异。时序的标准偏差大于不同版本的测量值之间的差异。

对于脚本的每个变体,执行了 10 次。在所有情况下$ARGV[0]都是3.5E5(350000)。

没有my $num = $ARGV[0]

$ perl measure.pl 
2.369921 2.38991 2.380969 4.419895 2.398861 2.420928 2.388721 2.368144 2.387212 2.386347
mean:  2.5910908
sigma: 0.609763793801797

my $num = $ARGV[0]

$ perl measure.pl 
4.435764 2.419485 2.403696 2.401771 2.411345 2.466776 4.408127 2.416889 2.389191 2.397409
mean:  2.8150453
sigma: 0.803721101668365

measure.pl脚本:

use strict; use warnings; use 5.016;
use List::Util 'sum';

my @times = map qx/perl your-algorithm.pl 3.5E5/, 1..10;
chomp @times;

say "@times";
say "mean:  ", mean(@times);
say "sigma: ", sigma(@times);


sub mean { sum(@_)/@_ }

sub sigma {
    my $mean = mean(@_);
    my $variance = sum(map { ($_-$mean)**2 } @_) / @_;
    sqrt $variance;
}

减少your-algorithm.pl以便只打印一个时间:

foreach (1..$ARGV[0]){$ans++ if ($h{$_}==89);}
print Time::HiRes::tv_interval($time), "\n";
于 2013-08-01T22:39:41.190 回答