Dear forum, my title explains to some extend what I am trying to achieve.
To make it hopefully clearer, I have written the following minimal code as an example.
First, I create an ordinary script (scriptA.jl
) where the desired functionality is implemented:
(1) there is a function called forallworkers
that is made available to all available workers
(2) there is a second function called caller
, available only to the process handling the REPL (is this the right way of putting it?) which calls function forallworkers
.
In my real problem, function forallworkers
implements some tedius and lengthy calculations and function caller
calls forallworkers
multiple times in parallel using pmap
while doing some extra calculations which are not relevant here. Hence, the user can comfortably call function caller
while being oblivious to the fact that there are computations that run in parallel.
If I start julia 1.5.3 with julia -O3 -p2
, load the script with include("scriptA.jl")
below
# scriptA.jl
# starting julia 1.5.3 with: julia -O3 -p2
@everywhere using SpecialFunctions, Printf
@everywhere function forallworkers(x)
@printf("Result from worker %d is %.3f\n", myid(), erf(x))
return erf(x)
end
function caller(X)
# some computation on X takes place here in the real problem,
# but is not relevant to this MWE
pmap(forallworkers, X)
end
and call caller(1:5)
, things will run as expected:
julia> caller(1:5)
From worker 3: Result from worker 3 is 0.995
From worker 2: Result from worker 2 is 0.843
From worker 3: Result from worker 3 is 1.000
From worker 2: Result from worker 2 is 1.000
From worker 3: Result from worker 3 is 1.000
5-element Array{Float64,1}:
0.8427007929497149
0.9953222650189527
0.9999779095030014
0.9999999845827421
0.9999999999984626
Now, I would like to put this functionality in a module (with the future intention of creating a package). My first attempt was:
# scriptB.jl
# starting julia 1.5.3 with: julia -O3 -p2
module modMWE
export caller
@everywhere using SpecialFunctions, Printf
@everywhere function forallworkers(x)
@printf("Result from worker %d is %.3f\n", myid(), erf(x))
return erf(x)
end
function caller(X)
# some computation on X takes place here in the real problem,
# but is not relevant to this MWE
pmap(forallworkers, X)
end
end
However, if I load scriptB.jl
immediately after starting julia with include("scriptB.jl")
, I get the message
"ERROR: LoadError: LoadError: UndefVarError: @everywhere not defined"
which I found odd since I started julia with two processes using the flag -p2
. Nevertheless, after inserting the line using Distributed
the problem seems to go away in scriptC.jl
:
# scriptC.jl
# starting julia 1.5.3 with: julia -O3 -p2
module modMWE
export caller
using Distributed # <------ newly added line
@everywhere using SpecialFunctions, Printf
@everywhere function forallworkers(x)
@printf("Result from worker %d is %.3f\n", myid(), erf(x))
return erf(x)
end
function caller(X)
# some computation on X takes place here in the real problem,
# but is not relevant to this MWE
pmap(forallworkers, X)
end
end
Now I can successfully load the module with include("scriptC.jl")
. However, if I now try and call function caller with modMWE.caller(1:5)
this results in the following error:
julia> modMWE.caller(1:5)
ERROR: UndefVarError: forallworkers not defined
Stacktrace:
[1] caller(::UnitRange{Int64}) at ./REPL[1]:15
[2] top-level scope at REPL[2]:1
My naive impression is that function forallworkers
should be available to all processes since its definition has been qualified with @everywhere
, but obviously this is not the case.
My question therefore:
- How can I properly create a module that has functions that visible to all workers so that they can be run in parallel?
- I.e. in this particular example this specifically translates to, how do I make function
forallworkers
properly available to all workers and callable within functioncaller
?
Many thanks!
EDIT: After solving the problem, I add here how the final version of the script (you can also find it below if you follow the discussion) that solves the problem.
# scriptE.jl
# starting julia 1.5.3 with: julia -O3 -p2
@everywhere module modMWE
export caller
using Distributed
using SpecialFunctions, Printf
function forallworkers(x)
@printf("Result from worker %d is %.3f\n", myid(), erf(x))
return erf(x)
end
function caller(X)
# some computation on X takes place here in the real problem,
# but is not relevant to this MWE
pmap(forallworkers, X)
end
end