Даже знаю Преждевременная оптимизация - корень всего зла
{
local $\ = "\n";
print foreach @numbers;
}
но некоторые ожидания могут быть ошибочными. Тест немного странный, потому что вывод может вызвать некоторые странные побочные эффекты, и порядок может быть важен.
#!/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);
}
Можно ожидать, что 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% --
Иногда я наблюдал постоянно loop1
примерно на 15-20% быстрее, чем loop2
, но я не могу определить, почему.
Я наблюдал сгенерированный байт-код для loop1 и loop2, и при создании переменной my
разница только одна. Эта переменная внутренняя область не выделяется и также не копируется, поэтому эта операция очень дешевая. Разница возникает, я думаю, только от конструкции "$_\n"
, которая недешева. Эти петли должны быть очень похожи
for (@numbers) {
...
}
for my $a (@numbers) {
...
}
но этот цикл дороже
for (@numbers) {
my $a = $_;
...
}
а также
print "$a\n";
дороже
print $a, "\n";