shemp has asked for the wisdom of the Perl Monks concerning the following question:

In my attempts to write more efficient code, i have come up with a few situations where i dont understand exactly what Perl is doing, and thus can't decide which way to code something for faster execution.

Basically i am trying to figure out when a function is called, and then exited, what sticks around for subsequent calls, and what is destroyed and needs to be recreated internally on each call.

# case 1 sub blah { ... my @list = qw(# list of things); foreach my $item (@list) { ... } # case 2 { my @list; BEGIN { @list = qw(# list of things); } sub blah { ... foreach my $item (@list) { ... } } # case 3 sub blah { ... foreach my $item qw(# list of things) { ... }
I'm assuming that @list is not going to ever change in blah().

In case 1, im pretty sure that @list is re-initialized on each call to blah()

In case 2, @list is initialized once, in the BEGIN{}, and never goes away, because of the closure.

case 3, i am not sure what happens. Does the inline list re-create itself on each call to blah(), or is it created once and sticks around somewhere? I'm uncertain about this one because the list is never assigned to a variable (as a whole), which makes me think that its sticking around somewhere.

I could ask similar questions about inlined regexs, etc.

UPDATE:
changed my blah {} to sub blah {} - as it should be.

Replies are listed 'Best First'.
Re: Resource allocation question
by revdiablo (Prior) on Oct 20, 2004 at 18:09 UTC
    the list is never assigned to a variable

    This is why it cannot "stick around." There is no place for this list to live. Lists are, by definition, temporary things. Unless you put the list into an array, and absent some under-hood optimization I am not aware of, it will disappear as soon as it is done with.

    On a side note, I think you might be engaging in what is commonly known as premature optimization, or even nano-optimization. I have not run the benchmarks, but I would be shocked to find the creation of the list has any impact on the actual performance of an application. I can understand the desire to know how perl works a bit better, but trying to use this type of thing as a real optimization would almost surely be fruitless.

Re: Resource allocation question
by ikegami (Patriarch) on Oct 20, 2004 at 19:51 UTC

    (btw, don't you mean sub blah instead of my blah)

    Benchmark it!

    use Benchmark qw( cmpthese ); $i=0; sub blah1 { my @list = qw(# list of things); foreach my $item (@list) { $i++; } } { my @list; BEGIN { @list = qw(# list of things); } sub blah2 { foreach my $item (@list) { $i++; } } } sub blah3 { foreach my $item qw(# list of things) { $i++; } } cmpthese(0, { blah1 => \&blah1, blah2 => \&blah2, blah3 => \&blah3, }); __END__ (partial) output ================ Rate blah1 blah2 blah3 blah1 118024/s -- -52% -53% blah2 245479/s 108% -- -1% blah3 248532/s 111% 1% --

    2 and 3 are equally fast, so you might as well use the cleaner 3.

      Ok good. Although the list in #3 never gets assigned to a variable, the interpreter certainly knows about it. So i was thinking about it in an analogous manner to when you have something like:
      if ( $x =~ /#some regex/o ) { # or if ( $x =~ /#some constant regex/ ) {
      Those regex's are only compiled once, whatever that means. I guess it means that the interpreter stores the info away somewhere to be readily available for use later.
Re: Resource allocation question
by JediWizard (Deacon) on Oct 20, 2004 at 17:53 UTC

    Im not sure, and have not tested this, but my guess would that Case 3 would be the most effecient. According to perlop qw() "generates a real list at compile time". It seems to me that would be the most efficient way of doing things. Of course at this point in the docs they are comparing qw() to split(' ', $STRING) but it does lead me to believe the list is created once, and simply sticks arround somewhere. But I could be wrong, and often am. Just my two cents.

    May the Force be with you
      I am more interested in whether the list sticks around, as opposed to the time to create with qw() or whatever. blah() would be a function that is called many, many times during execution, and i only want @list to be initialized once.