Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
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 taking refuge in the Monastery: (5)
As of 2025-07-14 06:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.