why are sub routine arguments slower to use than outer variables?
-
28-09-2019 - |
Question
Running the following code :
use strict;
use warnings;
use Benchmark;
my $defaultArray = [1,2,3,4];
sub VARIABLE {
my $arrayref = @_ ? $_[0] : $defaultArray;
return $arrayref->[0].$arrayref->[1].$arrayref->[2].$arrayref->[3];
}
Benchmark::cmpthese(
-10,
{
VARIABLE_DEFAULT => sub { VARIABLE() },
VARIABLE_NODEFAULT => sub { VARIABLE([4,3,2,1]) },
}
);
I get the following Benchmark results :
Rate VARIABLE_NODEFAULT VARIABLE_DEFAULT
VARIABLE_NODEFAULT 313631/s -- -74%
VARIABLE_DEFAULT 1210501/s 286% --
Why is the NODEFAULT version so much slower than the DEFAULT one ?
Solution
It's that much slower because you're creating a new anonymous array ref every time you call it. Change the code to this:
use strict;
use warnings;
use Benchmark;
my $defaultArray = [1,2,3,4];
sub VARIABLE {
my $arrayref = @_ ? $_[0] : $defaultArray;
return $arrayref->[0].$arrayref->[1].$arrayref->[2].$arrayref->[3];
}
Benchmark::cmpthese(
-10,
{
VARIABLE_DEFAULT => sub { VARIABLE() },
VARIABLE_NODEFAULT => sub { VARIABLE($defaultArray) },
}
);
And your benchmark ends up much nicer:
Rate VARIABLE_NODEFAULT VARIABLE_DEFAULT
VARIABLE_NODEFAULT 1065824/s -- -2%
VARIABLE_DEFAULT 1085082/s 2% --
OTHER TIPS
I'd say because DEFAULT uses one and the same array for every call while the NODEFAULT has to allocate and free space for the array for every call. Compare with the following:
Benchmark::cmpthese(
-10,
{
VARIABLE_DEFAULT => sub { VARIABLE() },
VARIABLE_NODEFAULT => sub { VARIABLE($defaultArray) },
}
);
Rate VARIABLE_NODEFAULT VARIABLE_DEFAULT VARIABLE_NODEFAULT 1619427/s -- -4% VARIABLE_DEFAULT 1689428/s 4% --
Got it. This is not the use of a parameter instead of an outer variable, but the test himself : VARIABLE_NODEFAULT => sub { VARIABLE([4,3,2,1]) }
In this line, we create an array. Not in this one : VARIABLE_DEFAULT => sub { VARIABLE() },
.