Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
I often use very deeply nested structures in my code. This can make for ugly code. $self->{thiskey}{theykey}{etc}="etc..."
I've been going back and cleaning up some older code by taking a ref to the HoHoHoHo..s and it got me to thinking about hashes in general( That and reading perlguts).

I always assumed that when you said $hash{'constant_key'}->{key2}, Perl would optimize this on compile and not keep fetching $hash{'constant_key'} after it first encountered it.

I thought wrong.
It would appear that using a reference to the desired "Hash in a Hash" has a fairly large performance implication. This very well may be a "Duh!" for others but for me this was very eye opening. Using a reference to a HoH speeds things up on average about 15%! A more practical test (HoH) bears this out. Not a bad speedup. On HoHoH it averages about 35% faster. The deeper the reference, the bigger the payoff.

I don't do a lot of benchmarking so if someone sees a flaw in my method, I'd appreciate feedback.

Lesson: So not only does using refs to nested data structures make your code easier to read, it makes it a good bit faster.
#!/usr/bin/perl use strict; use warnings; use Benchmark qw(cmpthese timethese); my $char = 'a'; my %hash = map {$char++.$_ => $_} (1..50); my %HoH = map {$char++.$_ => {%hash} } (1..20); my %HoHoH = map {$char++.$_ => {%HoH} } (1..50); my ($ref,$ref1,$ref2,$ref3,$ref4); $ref1->{key1} = {%hash}; $ref2->{key1}{key2} = {%hash}; $ref3->{key1}{key2}{key3} = {%hash}; $ref4->{key1}{key2}{key3}{key4} = {%hash}; my ($shortref,$shortref1,$shortref2,$shortref3,$shortref4) = ( \%hash, $ref1->{key1}, $ref2->{key1}{key2}, $ref3->{key1}{key2}{key3}, $ref4->{key1}{key2}{key3}{key4}, ); my $iterations = 10000; my @benchmarks = ( {count=> $iterations, hash=>sub { foreach my $k ( keys %ha +sh ) { $hash{$k}++ } }, ref=>sub { foreach my $k ( keys %{$shortref} ) { $shortre +f->{$k}++ } } }, {count=> $iterations, ref2hash1=>sub { foreach my $k ( key +s %{$ref1->{key1}}) { $ref1->{key1}{$k}++ }}, shortref1=>sub { foreach my $k ( keys %{$shortref1}) { $s +hortref1->{$k}++ }} }, {count=> $iterations, ref2hash2=>sub { foreach my $k ( key +s %{$ref2->{key1}{key2}}) { $ref2->{key1}{key2}{$k}++ }}, shortref2=>sub { foreach my $k ( keys %{$shortref2}) { $s +hortref2->{$k}++ }} }, {count=> $iterations, ref2hash3=>sub { foreach my $k ( key +s %{$ref3->{key1}{key2}{key3}}) { $ref3->{key1}{key2}{key3}{$k}++ }}, shortref3=>sub { foreach my $k ( keys %{$shortref3}) { $s +hortref3->{$k}++ }} }, {count=> $iterations, ref2hash4=>sub { foreach my $k ( key +s %{$ref4->{key1}{key2}{key3}{key4}}) { $ref4->{key1}{key2}{key3}{key +4}{$k}++ }}, shortref4=>sub { foreach my $k ( keys %{$shortref4}) { $s +hortref4->{$k}++ }} }, { count=>2000, HoH =>sub { foreach my $k (keys %HoH) { foreach (keys %{ $HoH{$k} } ){ $HoH{$k}->{$_}++; } } }, refHoH =>sub { foreach my $k (keys %HoH) { my $hashref = $HoH{$k}; foreach (keys %{ $hashref } ){ $hashref->{$_}++; } } }, }, { count=>100, HoHoH =>sub { # Traverse foreach my $k (keys %HoHoH) { foreach my $k2 (keys %{ $HoHoH{$k} } +){ foreach (keys %{ $HoHoH{$k}->{$k2} + } ){ $HoHoH{$k}{$k2}->{$_}++; } } } }, refHoHoH =>sub { # Traverse foreach my $k (keys %HoHoH) { my $hashref = $HoHoH{$k}; foreach (keys %{ $hashref } ){ my $hashref2 = $hashref->{$_}; foreach (keys %{$hashref2} ){ $hashref2->{$_}++; } } } }, }, ); foreach my $bench (@benchmarks){ my $results = timethese(delete $bench->{count} ,$bench); print "-" x 20,"\n"; cmpthese($results); print "-" x 40,"\n\n"; } __END__ Benchmark: timing 10000 iterations of hash, ref... hash: 2 wallclock secs ( 2.06 usr + 0.00 sys = 2.06 CPU) @ 48 +54.37/s (n=10000) ref: 2 wallclock secs ( 2.18 usr + 0.00 sys = 2.18 CPU) @ 45 +87.16/s (n=10000) -------------------- Rate ref hash ref 4587/s -- -6% hash 4854/s 6% -- ---------------------------------------- Benchmark: timing 10000 iterations of ref2hash1, shortref1... ref2hash1: 3 wallclock secs ( 2.47 usr + 0.00 sys = 2.47 CPU) @ 40 +48.58/s (n=10000) shortref1: 3 wallclock secs ( 2.20 usr + 0.00 sys = 2.20 CPU) @ 45 +45.45/s (n=10000) -------------------- Rate ref2hash1 shortref1 ref2hash1 4049/s -- -11% shortref1 4545/s 12% -- ---------------------------------------- Benchmark: timing 10000 iterations of ref2hash2, shortref2... ref2hash2: 3 wallclock secs ( 2.90 usr + 0.00 sys = 2.90 CPU) @ 34 +48.28/s (n=10000) shortref2: 2 wallclock secs ( 2.14 usr + 0.00 sys = 2.14 CPU) @ 46 +72.90/s (n=10000) -------------------- Rate ref2hash2 shortref2 ref2hash2 3448/s -- -26% shortref2 4673/s 36% -- ---------------------------------------- Benchmark: timing 10000 iterations of ref2hash3, shortref3... ref2hash3: 3 wallclock secs ( 3.35 usr + 0.00 sys = 3.35 CPU) @ 29 +85.07/s (n=10000) shortref3: 3 wallclock secs ( 2.23 usr + 0.00 sys = 2.23 CPU) @ 44 +84.30/s (n=10000) -------------------- Rate ref2hash3 shortref3 ref2hash3 2985/s -- -33% shortref3 4484/s 50% -- ---------------------------------------- Benchmark: timing 10000 iterations of ref2hash4, shortref4... ref2hash4: 4 wallclock secs ( 3.58 usr + 0.00 sys = 3.58 CPU) @ 27 +93.30/s (n=10000) shortref4: 2 wallclock secs ( 2.16 usr + 0.00 sys = 2.16 CPU) @ 46 +29.63/s (n=10000) -------------------- Rate ref2hash4 shortref4 ref2hash4 2793/s -- -40% shortref4 4630/s 66% -- ---------------------------------------- Benchmark: timing 2000 iterations of HoH, refHoH... HoH: 16 wallclock secs (10.01 usr + 0.00 sys = 10.01 CPU) @ 19 +9.80/s (n=2000) refHoH: 9 wallclock secs ( 8.98 usr + 0.00 sys = 8.98 CPU) @ 22 +2.72/s (n=2000) -------------------- Rate HoH refHoH HoH 200/s -- -10% refHoH 223/s 11% -- ---------------------------------------- Benchmark: timing 100 iterations of HoHoH, refHoHoH... HoHoH: 30 wallclock secs (28.75 usr + 0.01 sys = 28.76 CPU) @ 3 +.48/s (n=100) refHoHoH: 24 wallclock secs (22.49 usr + 0.00 sys = 22.49 CPU) @ 4 +.45/s (n=100) -------------------- Rate HoHoH refHoHoH HoHoH 3.48/s -- -22% refHoHoH 4.45/s 28% -- ----------------------------------------


-Lee

"To be civilized is to deny one's nature."

In reply to The Cost of Nested Referencing by shotgunefx

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others imbibing at the Monastery: (5)
    As of 2020-04-04 00:18 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?
      The most amusing oxymoron is:
















      Results (32 votes). Check out past polls.

      Notices?