I am quite new in Perl and I woud like to know which of the following loops is more efficient:
my @numbers = (1,3,5,7,9);
foreach my $current (@numbers){
print "$current\n";
}
or
my @numbers = (1,3,5,7,9);
foreach (@numbers){
print "$_\n";
}
I want to know this in order to know if the use of $_ is more efficient because is place in a register because is commonly used or not. I have written some code and I'm trying to clean it up and I've found out that I'm using the first loop more often than the second one.
Have you identified that there is a performance problem in sections of code that are making use of these loops? If not, you want to go for the one that is more readable and thus more maintainable. Any difference in speed will probably be negligible, especially compared to other parts of your system. Always code for maintainability first, then profile, then code for performance
"Premature optimisation is the root of all evil"[1]
[1] Knuth, Donald. Structured Programming with go to Statements, ACM Journal Computing Surveys, Vol 6, No. 4, Dec. 1974. p.268.
Even know Premature optimisation is the root of all evil
{
local $\ = "\n";
print foreach @numbers;
}
but some expectations can be wrong. Test is little bit weird because output can make some weird side-effects and order can be important.
#!/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);
}
One can expect that loop2 should be faster than 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% --
Sometimes I observed consistently loop1
about 15%-20% faster than loop2
but I can't determine why.
I was observed generated byte-code for loop1 and loop2 and there is difference only one when creating my
variable. This variable interior is not allocated and also not copied thus this operation is very cheap. Difference comes I think only from "$_\n"
construct which is not cheap. These loops should be very similar
for (@numbers) {
...
}
for my $a (@numbers) {
...
}
but this loop is more expensive
for (@numbers) {
my $a = $_;
...
}
and also
print "$a\n";
is more expensive than
print $a, "\n";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With