Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

keys vs values performance

Tags:

hash

perl

I would like to know theoretical background of hash values performing better than keys, and whether perldoc covers this topic.

use strict;
use warnings;
use Benchmark qw(:all);

my %hash = 1 .. 30_000;

cmpthese(-3, {
  values => sub {
    for my $v (values %hash) { }

  },
  keys => sub {
    for my $v (keys %hash) { }
  },
  avalues => sub {
    for my $v (@{[ values %hash ]}) { }
  },
  akeys => sub {
    for my $v (@{[ keys %hash ]}) { }
  },
});

__DATA__
         Rate   akeys    keys avalues  values
akeys   196/s      --    -33%    -56%    -71%
keys    294/s     50%      --    -35%    -57%
avalues 451/s    130%     54%      --    -33%
values  677/s    245%    131%     50%      --

perl is 5.20.0

like image 570
mpapec Avatar asked Dec 18 '22 16:12

mpapec


1 Answers

The keys aren't stored in the hash as scalar. A string scalar must therefore be created for each key returned by keys.

On the other hand, the values are stored as scalars in the hash, and those very scalars are returned by values. Nothing copied but a pointer.


The above can be demonstrated using using the following benchmark:

use strict;
use warnings;

use Benchmark qw( cmpthese );

my %sm_hash = map {                    sprintf('%04d', $_) } 1 .. 1000*2;
my %lg_hash = map { ( "x" x 10_000 ) . sprintf('%04d', $_) } 1 .. 1000*2;

cmpthese(-3, {
   sm_values => sub { 1 for values %sm_hash },
   lg_values => sub { 1 for values %lg_hash },
   sm_keys   => sub { 1 for keys   %sm_hash },
   lg_keys   => sub { 1 for keys   %lg_hash },
});

Output:

             Rate   lg_keys   sm_keys lg_values sm_values
lg_keys    5286/s        --      -19%      -57%      -58%
sm_keys    6532/s   ==> 24%        --      -47%      -48%
lg_values 12247/s      132%       87%        --       -2%
sm_values 12517/s      137%       92%    ==> 2%        --

As you can see, then length of the keys has an effect on how long it takes for keys to be evaluated, but the length of the values has no effect on how long it takes for values to be evaluated.


A simpler but less definitive demonstration comes in the form of an attempt to modify the values returned by keys and values.

for (keys(%h)) {
   $_ = uc($_);  # Has no effect on the hash.
}

for (values(%h)) {
   $_ = uc($_);  # Effects the hash.
}
like image 139
ikegami Avatar answered Jan 02 '23 03:01

ikegami