Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: Not-so-Simple Switch statement

by NetWallah (Canon)
on Sep 13, 2003 at 21:46 UTC ( [id://291296]=note: print w/replies, xml ) Need Help??


in reply to Simple Switch statement

I embellished liz's benchmark, adding another implementation of the "switch" equivalent, and ran some tests.

I use a hash to store subroutine references, and index into the hash. This requires the same amount of code as the other methods, but I feel it is more "Perly". I think it is also more scalable.

Performance-wise, the hash runs almost neck-and-neck to the "if" - see the benchmark below.

I'm seeking feedback regarding the coding of the line 6=> sub {$switch{5}()}, - perhaps there is a better way to express that.

Here is the benchmark code and results:

use strict; use Benchmark; # The Declarative part has been take out of the loop my %switch; %switch = ( 1=> sub{print STDERR '1'}, 2=> sub{print STDERR '2'}, 3=> sub{print STDERR '3'}, 4=> sub{print STDERR '4'}, 5=> sub{print STDERR '5 or 6'}, 6=> sub {$switch{5}()}, fred=> sub{print STDERR 'fred'}, __DEFAULT__=>sub{print STDERR 'default'}, ); my @loopList; for (my $count=10; $count < 100; $count +=10){ @loopList = (1..$count, 'fred'); printf "\n====== Benchmark for %.1f%% match rate (Count= %3d)===\ +n" , 7 * 100 / ($count + 1), $count; RunTest(); } ########################## sub RunTest{ timethese( 10**4 ,{ switch => sub { sub switch{ eval{ goto "case_$_[0]" } or goto default; } for my $expr ( @loopList ) { switch( $expr ); { case_1: print STDERR '1'; last; case_2: print STDERR '2'; last; case_3: print STDERR '3'; last; case_4: print STDERR '4'; last; case_5: ; case_6: print STDERR '5 or 6'; last; case_fred: print STDERR 'fred'; last; default: print STDERR "default"; } } }, #/switch=>sub if => sub { for my $expr ( @loopList ) { if ($expr eq '1') {print STDERR '1'} elsif ($expr eq '2') {print STDERR '2'} elsif ($expr eq '3') {print STDERR '3'} elsif ($expr eq '4') {print STDERR '4'} elsif ($expr eq '5' or $expr eq '6') {print STDERR '5 or 6'} elsif ($expr eq 'fred') {print STDERR 'fred'} else {print STDERR "default"} } },#/if=>sub HashSub => sub{ for my $expr ( @loopList ) { #print "Iter=$expr;\n"; if( exists $switch{$expr}){ $switch{$expr}() }else{ $switch{__DEFAULT__}(); }; }; #/for },#/UseHash } ); #/TimeThese }#/RunTest
--------------------------------------
Results:
>perl switchtest.pl 2> NUL ====== Benchmark for 63.6% match rate (Count= 10)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 1 wallclock secs ( 0.52 usr + 0.10 sys = 0.62 CPU) @ 16 +129.03/s ( n=10000) if: 0 wallclock secs ( 0.41 usr + 0.09 sys = 0.50 CPU) @ 19 +960.08/s ( n=10000) switch: 6 wallclock secs ( 5.64 usr + 0.12 sys = 5.76 CPU) @ 17 +36.71/s (n =10000) ====== Benchmark for 33.3% match rate (Count= 20)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 1 wallclock secs ( 0.92 usr + 0.22 sys = 1.14 CPU) @ 87 +56.57/s (n =10000) if: 1 wallclock secs ( 0.81 usr + 0.15 sys = 0.96 CPU) @ 10 +395.01/s ( n=10000) switch: 18 wallclock secs (17.04 usr + 0.34 sys = 17.38 CPU) @ 57 +5.24/s (n= 10000) ====== Benchmark for 22.6% match rate (Count= 30)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 1 wallclock secs ( 1.39 usr + 0.28 sys = 1.67 CPU) @ 59 +80.86/s (n =10000) if: 2 wallclock secs ( 1.03 usr + 0.38 sys = 1.41 CPU) @ 70 +77.14/s (n =10000) switch: 29 wallclock secs (28.98 usr + 0.49 sys = 29.47 CPU) @ 33 +9.29/s (n= 10000) ====== Benchmark for 17.1% match rate (Count= 40)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 3 wallclock secs ( 1.73 usr + 0.47 sys = 2.20 CPU) @ 45 +41.33/s (n =10000) if: 1 wallclock secs ( 1.51 usr + 0.36 sys = 1.87 CPU) @ 53 +39.03/s (n =10000) switch: 42 wallclock secs (41.10 usr + 0.66 sys = 41.76 CPU) @ 23 +9.46/s (n= 10000) ====== Benchmark for 13.7% match rate (Count= 50)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 3 wallclock secs ( 2.29 usr + 0.44 sys = 2.73 CPU) @ 36 +58.98/s (n =10000) if: 2 wallclock secs ( 1.94 usr + 0.38 sys = 2.32 CPU) @ 43 +02.93/s (n =10000) switch: 54 wallclock secs (52.90 usr + 0.66 sys = 53.56 CPU) @ 18 +6.72/s (n= 10000) ====== Benchmark for 11.5% match rate (Count= 60)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 3 wallclock secs ( 2.55 usr + 0.71 sys = 3.27 CPU) @ 30 +62.79/s (n =10000) if: 3 wallclock secs ( 2.35 usr + 0.43 sys = 2.78 CPU) @ 35 +91.95/s (n =10000) switch: 66 wallclock secs (64.62 usr + 0.90 sys = 65.52 CPU) @ 15 +2.62/s (n= 10000) ====== Benchmark for 9.9% match rate (Count= 70)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 4 wallclock secs ( 3.06 usr + 0.74 sys = 3.80 CPU) @ 26 +34.35/s (n =10000) if: 3 wallclock secs ( 2.63 usr + 0.61 sys = 3.24 CPU) @ 30 +82.61/s (n =10000) switch: 78 wallclock secs (76.56 usr + 0.89 sys = 77.45 CPU) @ 12 +9.11/s (n= 10000) ====== Benchmark for 8.6% match rate (Count= 80)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 4 wallclock secs ( 3.52 usr + 0.79 sys = 4.32 CPU) @ 23 +16.96/s (n =10000) if: 4 wallclock secs ( 3.04 usr + 0.66 sys = 3.70 CPU) @ 26 +99.06/s (n =10000) switch: 89 wallclock secs (88.21 usr + 1.31 sys = 89.52 CPU) @ 11 +1.71/s (n= 10000) ====== Benchmark for 7.7% match rate (Count= 90)=== Benchmark: timing 10000 iterations of HashSub, if, switch... HashSub: 5 wallclock secs ( 3.96 usr + 0.89 sys = 4.85 CPU) @ 20 +63.13/s (n =10000) if: 5 wallclock secs ( 3.39 usr + 0.77 sys = 4.17 CPU) @ 24 +00.38/s (n =10000) switch: 101 wallclock secs (100.08 usr + 1.37 sys = 101.46 CPU) @ + 98.56/s ( n=10000) >

Replies are listed 'Best First'.
2Re: Not-so-Simple Switch statement
by bart (Canon) on Sep 13, 2003 at 22:36 UTC
    When doing such benchmarks, one should remember that printing is a very slow process. Even more, the time it takes is likely not very constant. So in order to get a real feel for how long the code-under-test really takes, you should do something fast and harmless, like setting a variable. So I replaced everything looking like
    print STERR 'foo';
    with
    $out = 'foo';

    I do get quite different results than yours. I always get the faster result for "HashSub" over "if", while with you, it's slower. Odd.

      I re-ran the tests too, replacing the "print STDERR" with an assignment.

      The "if" and "HashSub" methods speeds converge faster, with Hashsub becoming faster than "if" at a 22% match rate.

      The minor differences in results may have to do with OS and perl implementations. I'm running Activestate perl 5.8 under Windows XP.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://291296]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-04-24 01:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found