Avoiding module __init__ being called multiple times

Hello, I have been porting a web service I have to Genie. I have found the default structure very helpful to organize my project (auto-loading of libs, controller default structure, etc).

I have the following problem:

  • a lib/LanguageUtils.jl module that uses PyCall to import a bunch of libraries (__init__). This adds a ~30s cost per instantiation of the module (using LanguageUtils) and gets autoloaded by Genie.
  • Multiple controllers using this module.
  • using seems to trigger another call to __init__, with the consequent delay. I can sidestep this by setting an ENV["LANGUAGE_INIT"]=true flag, but that will cause problems (objects not being loaded). So it seems like every time using is called for a local module, it’s quite expensive.

I always feel like separating code in local modules in Julia is sort of anti-pattern or makes things more difficult.

Am I doing something wrong or are there any patterns I should use/ know about?

Thanks in advance.

That sounds wrong.

In particular, if you define a function __init__() in a module, then Julia will call __init__() immediately after the module is loaded (e.g., by import , using , or require ) at runtime for the first time (i.e., __init__ is only called once, and only after all statements in the module have been executed).

There may be another issue with code you have that makes it look as though, at runtime, LanguageUtils.__init__ is called again after is first run.

"a lib/LanguageUtils.jl module that uses PyCall to import … libraries (__init__). "
Are you saying: LanguageUtils.jl is a module that defines an __init__() function and this __init__() function imports libraries using PyCall?

I always feel like separating code in local modules in Julia
is sort of anti-pattern or makes things more difficult.

Using local modules in Julia to separate specifically purposed code is the best way to introduce a namespace to qualify the purpose your code fulfills.
Separation-of-concerns in software design is a worthwhile perspective.

Using a local module to make your work better apportioned now and easier when revisiting the work (then when it may appear somewhat less fresh) does just that.
Local modules are infrequently needed, though. Nonetheless, where appears __init__() there is a module to be initialized, and it may be a local module.

Are you importing from the local module correctly? Does the local module access both enclosing modules and also other unnested modules properly? Is your local module an inner (wrapped) module or is it an “alongside” module? Should it be?
https://docs.julialang.org/en/v1/manual/modules/#Submodules-and-relative-paths

Are you saying: LanguageUtils.jl is a module that defines an __init__() function and this __init__() function imports libraries using PyCall?

Yes.

Using local modules in Julia to separate specifically purposed code is the best way to introduce a namespace to qualify the purpose your code fulfills

Absolutely :slight_smile: I don’t doubt the idea of code separation in general, just that I was finding it somehow impractical in this case.

Are you importing from the local module correctly? Does the local module access both enclosing modules and also other unnested modules properly? Is your local module an inner (wrapped) module or is it an “alongside” module? Should it be?

I am relying on Genie’s auto-loading feature, which “recursively adds all the folders to the LOAD_PATH”.

I could try doing using ..LanguageUtils and making sure the module hierarchy is correctly defined, but then I guess it kind of defeats the purpose of the auto-loading. But maybe there’s a good reason not to do it on the first place.

Does the local module access both enclosing modules and also other unnested modules properly?
I think all modules are self-contained, with the exception of LanguageUtils being used on several places. There’s no deeper nesting. I agree that this behaviour does not seem normal.

Perhaps it’s easily sidestepped, though. Thanks for the hints, I’ll see if I find any errors and will try to call it using a relative path in this case and come nack with the results.