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

In an earlier post I asked about require, if using it multiple times would slow things down. As merlyn explains, require is just a hash look up.

Going back to some of my code, I removed some use directives and put them as require directives inside subs and methods. This sped things up a lot for some procedures. Where I have used web apps, this has helped tremendously.

The next question I have is about the 'use' statement.

My basic question is do multiple use statements cause as little expense as multiple require statements? I know that use runs at compile time where require at run time, does this relate to the answer, how?

Long version of my question:

What if I three packages; A, B1, and B2. All three packages 'use' C. A imports B1 and B2. (pseudocode)

package A; use C; use B1; use B2; 1; package B1; use C; 1; package B2; use C; 1;

Does package C get loaded 3 times?
If C exports into into all three namespaces, does it slow things down?
(Should I be looking into coding C instead, for this kind of nitpicking?)

This is a loose example, what I am concerned with are more intricate dependencies, bigger things.

  • Comment on Do multiple use statements across module dependency hierarchies require as little expense as multiple require statements?
  • Download Code

Replies are listed 'Best First'.
Re: Do multiple use statements across module dependency hierarchies require as little expense as multiple require statements?
by stvn (Monsignor) on Jan 10, 2008 at 19:03 UTC
    Does package C get loaded 3 times?

    No.

    If C exports into into all three namespaces, does it slow things down?

    Yes, exports take time, have a gander at Exporter.pm's source to see what I mean.

    Going back to some of my code, I removed some use directives and put them as require directives inside subs and methods. This sped things up a lot for some procedures

    This is most likely because use will be executed at compile time, meaning all use statements will be executed (and the modules loaded) no matter where they are (yes, even if they are inside subs). Whereas require will execute at runtime and a require statement within a sub will not be executed until that sub is run.

    So I suspect that the speed up you are seeing is that now your modules are being loaded on-demand instead of all at compile time. This essentially spreads out the weight of the module loading (and potentially in some cases, does not do it at all).

    Now, if this is a webapp (as you seemed to indicate) and you are planning to deploy this under vanilla CGI, then this kind of optimization is a win. However if you deploy this under mod_perl or FastCGI (or some other "persistent interpreter" solution) then you are better off sticking with use.

    -stvn

      Ah! Very wonderful of you to point out the mod_perl gotcha! Indeed, require would be a catastrophe under this environment? The calls would be unavailable or the whole thing would have to be recompiled, etc?

      Yes, as you speak. The modules are loaded on call, not by default. And that is why it runs fast, because what's not "used" is not sought.

      This is not just useful in cgi by any stretch of the imagination.
      This is also *incredibly* useful in command line apps that may be able to do various different things.
      Or maybe your script has a %50 chance of failure for some reason, and should exit as soon as possible.
      For example, things on cron, that maybe have to do an expensive task at any moment, and are checking every 60 seconds if this procedure should or not happen.
      The require would not be reached unless conditions are met, thus, quick and cheap.

      Really helps speed things up, with an interpreted language.

        Ah! Very wonderful of you to point out the mod_perl gotcha! Indeed, require would be a catastrophe under this environment? The calls would be unavailable or the whole thing would have to be recompiled, etc?

        In a persistent and forking environment, the more likely-constant items you load into memory before forking, the more you can share between processes with copy-on-write memory. If most processes will use a module and you don't load it before you fork, each one will suffer the stat calls and loading time and importing time and use non-shared memory to load the code. If you do load before the fork, you only pay for the loading and compilation time once, and all subsequent processes will transparently use the same memory pages.

Re: Do multiple use statements across module dependency hierarchies require as little expense as multiple require statements?
by dragonchild (Archbishop) on Jan 10, 2008 at 20:07 UTC
    The biggest expense is going to be if you have a very large @INC that you're searching across. If files are located further down in @INC, such as if you're loading stuff you installed from CPAN, or if some of your @INC directories are on NFS mounts, those are going a much longer time to resolve than any import/export stuff you're dealing with.

    As for import/export stuff, I have a policy in my CPAN modules to never import stuff into my namespace, preferring instead to do the following:

    use Scalar::Util (); if ( Scalar::Util::reftype( $thing ) eq 'HASH' ) { # Do stuff here }
    This has a couple benefits (other than performance, which I wasn't thinking of) to my thinking:
    • Almost everything of mine is OO. Perl's OO treats all subroutines in a given namespace as methods in that class. I want to keep my classes as clean as possible, particularly if I want to have an AUTOLOAD.
    • External subroutines are immediately labelled as to where they come from for future maintainers. While some people aren't as thrilled by this, I have been stymied by automatic exports and where they came from.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Do multiple use statements across module dependency hierarchies require as little expense as multiple require statements?
by CountZero (Bishop) on Jan 10, 2008 at 18:48 UTC
    (From the top of my head) As use is just a require + export wrapped in a BEGIN block at least the require part will be constant and C will get loaded only once. You will have (possibly) three exports depending on which symbols (if any) you wish to import in your namespace(s), but I think that will take very little time.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      If C exports into all three namespaces, then I would expect this to involve three distinct exports (even if the exact same set of symbols is exported each time) because the symbols are being exported into three distinct namespaces.