Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re^2: eval string possibilities

by erix (Prior)
on Nov 22, 2004 at 04:36 UTC ( [id://409480]=note: print w/replies, xml ) Need Help??


in reply to Re: eval string possibilities
in thread eval string possibilities

Yes, my specific question I could probably find out by testing myself, but I learned about Benchmark only a short while ago. It will probably be a little tricky to factor out things that are not related to the to-eval-or-not-eval question.

And you are right; the little example is from the Cougar book, and my question springs from a program I started years ago based on it, and is still in use. It has grown (maybe even too much ;), and I find myself wondering what I will lose/gain by rewriting it.

Thanks for your reply.

Replies are listed 'Best First'.
Re^3: eval string possibilities
by revdiablo (Prior) on Nov 22, 2004 at 18:17 UTC
    I learned about Benchmark only a short while ago. It will probably be a little tricky to factor out things that are not related to the to-eval-or-not-eval question.

    In cases like this, I have learned that it's usually better to post bad code than no code at all. A small example written with Benchmark would have given repliers something to work with. They likely would have pointed out any flaws in the benchmark, and posted a modified version.

    There is a danger in this, though. Sometimes the code has small unrelated problems that derail the conversation, but I think this is a small price to pay. In my experience, posts containing pertinent code almost always get better replies.

    Sorry for the off-topic reply, but I think it will be useful for future posts. Hopefully you can avoid making some of the mistakes that I have made here at the Monastery. :-)

      Thanks for that advice, and I'll follow it up immediately with the script below, which I made after the OP and which is probably indeed bad code, although I think it does give the time discrepancies that I am looking for (qr much faster than eval). I suppose the main thing I missed all along (I had been told things in CB before), is the slowness of eval. Well, now I know :)

      #!/usr/bin/perl -w use strict; use warnings; use Benchmark qw /cmpthese/; cmpthese 10_000 => { 'do_eval' => sub { do_eval() }, 'do_qr' => sub { do_qr() }, }; sub do_eval { my $genome = "AGTATCGATCGATGCATGCTAGCTAGCTAGCTAGCTAGCTAGSTGCTAGCT"; my @regexes = ('abc', '^qwerty'); # dont care my $count = 0; my $code = 'if ($genome =~ /' . join ('/ && /', @regexes) . '/) { + $count++; }'; eval $code; die "Error: $@\n Code:\n$code\n" if ($@); } sub do_qr { my $string = "AGTATCGATCGATGCATGCTAGCTAGCTAGCTAGCTAGCTAGSTGCTAGCT"; my @regexes = ("abc", "^qwerty"); # dont care my $count = 0; my @compiled = map qr/$_/, @regexes; for(my $i=0; $i<@regexes; $i++) { if($string =~ /$compiled[$i]/){ $count++; } } } __END__ Rate do_eval do_qr do_eval 2162/s -- -77% do_qr 9242/s 328% --

        An important part of making benchmark code is to ensure the alternatives do the same thing. Your do_eval subroutine had a minor problem (you only had =~ $genome on the first match, instead of all of them), which I corrected. But then when I looked at the output from the two subroutines, I noticed it was different:

        sub do_eval { my $genome = "AGTATCGATCGATGCATGCTAGCTAGCTAGCTAGCTAGCTAGSTGCTAGCT"; my @regexes = ('AGT', 'ATC'); # dont care my $count = 0; my $code = 'if (' . join(' && ', map { "\$genome =~ /$_/" } @regexes) . ') { $count++; }'; eval $code; die "Error: $@\n Code:\n$code\n" if ($@); return $count; # returns 1 } sub do_qr { my $string = "AGTATCGATCGATGCATGCTAGCTAGCTAGCTAGCTAGCTAGSTGCTAGCT"; my @regexes = ("AGT", "ATC"); # dont care my $count = 0; my @compiled = map qr/$_/, @regexes; for(my $i=0; $i<@regexes; $i++) { if($string =~ /$compiled[$i]/){ $count++; } } return $count; # returns 2 }

        To fix that, I changed your do_eval sub to the following:

        sub do_eval { my $genome = "AGTATCGATCGATGCATGCTAGCTAGCTAGCTAGCTAGCTAGSTGCTAGCT"; my @regexes = ('AGT', 'ATC'); # dont care my $count = 0; my $code = join ";", map { "\$count++ if \$genome =~ /$_/" } @regexes; eval $code; die "Error: $@\n Code:\n$code\n" if ($@); return $count; # returns 2 }

        And I decided to add my own take on the matter, which generates One Big Regex, rather than a bunch of them:

        sub do_genre { my $genome = "AGTATCGATCGATGCATGCTAGCTAGCTAGCTAGCTAGCTAGSTGCTAGCT"; my @regexes = ("AGT", "ATC"); # dont care my $regex = join "|", map "($_)", @regexes; my $count = () = $genome =~ /$regex/; return $count; # returns 2 }

        When I run the benchmark, I get the following results:

        Rate do_eval do_qr do_genre do_eval 15531/s -- -65% -90% do_qr 44671/s 188% -- -72% do_genre 157893/s 917% 253% --

        Which just goes to show that the string eval is slow, but the looping is even slower. A different algorithm makes a big difference.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (8)
As of 2024-04-19 09:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found