synistar has asked for the wisdom of the Perl Monks concerning the following question:
I often times find myself putting c like switch statements into my code (mostly CGI apps). And since there is no "official" perl way to do this I just use the one that is most aesthetically pleasing to me.
foreach $tmp (@{$input})
{
SWITCH:
{
if($tmp =~m/$regex1/)
{
last SWITCH;
}
if($tmp =~m/$regex2/)
{
last SWITCH;
}
if($tmp eq '..')
{
last SWITCH;
}
if($tmp eq '.')
{
last SWITCH;
}
### DEFAULT
unless(-d "$path$tmp")
{
push @tmparr, $tmp;
}
}
}
So, since there are so many ways to code switch/case constructs in perl (half a dozen in the camel book alone), which way is the most efficient as far as execution speed goes? Has anyone benchmarked this?
Re: What is the most efficient perl switch/case statement?
by Abigail-II (Bishop) on Nov 21, 2003 at 14:46 UTC
|
That's a bit hard to benchmark, as it will depend on what
is being switched, how many cases there are, and what the
frequency of the cases is.
For instance, if there are a hundred cases, and each case
is taken about 1 out of 100 times, a hash based solution
might be best. If all the cases are small non-negative
integers, then an array based solution is to be preferred.
But if one case is taken far more than any other, an if/elsif
chain, with the common case first might be the most efficient
solution.
Abigail | [reply] |
Re: What is the most efficient perl switch/case statement?
by hardburn (Abbot) on Nov 21, 2003 at 14:51 UTC
|
Most of the switch structures used in Perl scale linearly. They're all pretty much the same. The only exception to this is a hash that stores references to subroutines (example on page 282 of the Blue Camel).
As pg recently pointed out, hashes have an absolute worst case runtime of O(n), but that case is so unlikely that it can be safely ignored (and perl's specific implementation does tricks to help make sure it won't happen). In the common case, hashes run very close to O(1).
Note, though, that the constant value of hash searching is larger than a simple if tree, so if you have a small number of cases, the ifs might still be faster. If you're comparing integer, you could use a regular array instead of a hash, which will always give you O(1) efficiency with a much smaller constant.
---- I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer
: () { :|:& };:
Note: All code is untested, unless otherwise stated
| [reply] [d/l] [select] |
Re: What is the most efficient perl switch/case statement?
by jeffa (Bishop) on Nov 21, 2003 at 14:53 UTC
|
This doesn't answer your question, but i'd rather use a dispatch table (a lookup hash) instead
of Switch ... but i rarely care about premature
optimization. In your case, you are also checking regexes,
so i would probably use Tie::Hash::Regex like so:
use strict;
use warnings;
use Tie::Hash::Regex;
tie my %hash, 'Tie::Hash::Regex';
%hash = (
'foo.txt' => 1,
'bar.html' => 2,
'..' => undef,
'.' => undef,
DEFAULT => undef,
);
my $arg = shift || 'DEFAULT';
my $candidate = $hash{$arg};
die "invalid arg\n" unless $candidate;
print "$candidate\n";
Since most of my work is Web based, i care more about
maintainability and readability than efficiency .. but i
do care about efficiency when it really matters.
UPDATE:
I forgot to mention CGI::Application which uses
a dispatch table to control which runmode your CGI is in.
If you haven't seen it yet, you really should RTFM on
CGI::App ...
| [reply] [d/l] |
|
Actually, I do use CGI::Application. And I have used hashes as dispatch tables before (actually reinvented that wheel myself after dipping my toe in some assembly code). I usually use switch type statements for combining regex tests and other kinds of comparisons/tests (like in the example). I was not aware of Tie::Hash::Regex however. That is something I will rtfm on. CPAN is so massive I find it hard to keep up with it all (and that is a good thing).
UPDATE:Tie::RegexpHash also seems like a pertinent module to check out. It allows one to use regexes as hash keys.
| [reply] |
Re: What is the most efficient perl switch/case statement?
by duff (Parson) on Nov 21, 2003 at 15:30 UTC
|
So, since there are so many ways to code switch/case constructs in perl (half a dozen in the camel book alone), which way is the most efficient as far as execution speed goes?
It seems to me that you should be more interested in which method is easiest to understand. Programmer time is always worth more than CPU time. I usually use an if/elsif/else ladder since most programmers can figure out what that's doing even if they're weak on perl skills.
But if you're really interested in which is faster, develop a large data set that would cause each branch to succeed individually or all fail, and then apply that data set to a particular switch construct. Mostly though, I think you'll be benchmarking your ability to implement the switch (And the test) rather than the particular switch-style.
Update: Fine. For the pedants out there: Programmer time is almost always worth more than CPU time. Of course there are situations where execution speed is critical. In my experience though, if you're programming in perl, execution speed isn't your top concern. :-)
| [reply] |
|
| [reply] |
|
I realize you are making a general point, but it seems unlikely that choosing the slowest switch statement implementation in Perl will cause any aircraft to go down. People learning programming should be aware that micro-optimizations of this kind rarely have any significant payoff, and are typically only worth doing after using a profiler to see where the problems lie.
| [reply] |
|
|
|
|
Re: What is the most efficient perl switch/case statement?
by fhe (Novice) on Nov 23, 2003 at 20:48 UTC
|
| [reply] |
Re: What is the most efficient perl switch/case statement?
by Anonymous Monk on Nov 21, 2003 at 15:02 UTC
|
So, since there are so many ways to code switch/case constructs in perl (half a dozen in the camel book alone), which way is the most efficient as far as execution speed goes? Has anyone benchmarked this?
Does it matter ( seems insignificant if you ask me)?
Why don't you benchmark it?
| [reply] |
|
|