Subject: | Slow on random access |
I've noticed that Tie::Hash::Rank is slow when it comes to random
read/write access to the tied hash, or for write once-read once hashes.
The attached patch introduces a new RECALCULATE option 'onfetchchange'
which will trigger a recalculation of the ranking only if fetching a
value after hash has been changed (value added/removed), instead of on
every fetch.
I hope you'll consider applying the patch to the next version.
Subject: | Tie-Hash-Rank-dirty.bench |
Message body not shown because it is not plain text.
Subject: | Tie-Hash-Rank-dirty.patch |
--- Rank.pm.orig 2001-06-13 21:55:08.000000000 +0200
+++ Rank.pm 2010-11-11 16:27:18.000000000 +0100
@@ -13,7 +13,8 @@
RECALCULATE => 'onstore',
@_,
_RANKS => {}, # yes, these go AFTER the parameters
- DATA => {}
+ DATA => {},
+ _DIRTY => 0,
};
return bless $self, $class;
@@ -43,6 +44,7 @@
}
$prevkey = $key;
}
+ $self->{_DIRTY}=0;
}
sub CLEAR { my $self=shift; $self->{DATA}={}; $self->{_RANKS}={}; }
@@ -50,11 +52,13 @@
my($self, $key, $value)=@_;
$self->{DATA}->{$key}=$value;
$self->_recalculate() if($self->{RECALCULATE} eq 'onstore');
+ $self->{_DIRTY}=1 if($self->{RECALCULATE} eq 'onfetchchange');
}
sub FETCH {
my $self=shift;
my $key=shift;
$self->_recalculate() if($self->{RECALCULATE} eq 'onfetch');
+ $self->_recalculate() if($self->{RECALCULATE} eq 'onfetchchange' && $self->{_DIRTY}==1);
return $self->{_RANKS}->{$key};
}
sub FIRSTKEY {
@@ -72,6 +76,7 @@
delete $self->{_RANKS}->{$key};
delete $self->{DATA}->{$key};
$self->_recalculate() if($self->{RECALCULATE} eq 'onstore');
+ $self->{_DIRTY}=1 if($self->{RECALCULATE} eq 'onfetchchange');
}
sub EXISTS {
my $self = shift;
@@ -131,12 +136,13 @@
=item C<RECALCULATE>
-Can be either C<onstore> or C<onfetch>, and defaults to 'onstore'. This
-determines when the module recalculates the ranks. 'onstore' makes it
-recalculate whenever you add a value to the hash, and 'onfetch' whenever
-you retrieve a value. Use this option if you need to tune your hash
-for data which is mainly read or mainly written, although it will make
-very little difference for small data-sets.
+Can be either C<onstore>, C<onfetch>, C<onfetchchange> and defaults to
+'onstore'. This determines when the module recalculates the ranks. 'onstore'
+makes it recalculate whenever you add a value to the hash, 'onfetch' whenever
+you retrieve a value, and 'onfetchchange' whenever you retrieve a value from a
+changed hash. Use this option if you need to tune your hash for data which is
+mainly read or mainly written, although it will make very little difference for
+small data-sets.
=back
Subject: | tie_rank_bench.pl |
#!/usr/bin/perl
use strict;
use Benchmark qw/cmpthese :hireswallclock/;
use Tie::Hash::Rank;
my %hash = ();
for ( my $i = 0 ; $i < 2_000 ; $i++ ) {
$hash{ 'FooBar' . $i } = int( rand(100_000) % 50_000 );
}
cmpthese(
10,
{
'onstore' => sub {
tie my %onstore, 'Tie::Hash::Rank', ( RECALCULATE => 'onstore' );
%onstore = %hash;
join '', map { $onstore{$_} } keys %onstore;
untie %onstore;
},
'onfetch' => sub {
tie my %onfetch, 'Tie::Hash::Rank', ( RECALCULATE => 'onfetch' );
%onfetch = %hash;
join '', map { $onfetch{$_} } keys %onfetch;
untie %onfetch;
},
'onfetchchange' => sub {
tie my %onfetchchange, 'Tie::Hash::Rank',
( RECALCULATE => 'onfetchchange' );
%onfetchchange = %hash;
join '', map { $onfetchchange{$_} } keys %onfetchchange;
untie %onfetchchange;
},
}
);