I would like to take an arbitrary function at runtime that may or may not be defined with the @everywhere
macro, and run it in a distributed way.
My first, naive attempt was to simply try and use the function inside of pmap
@assert nprocs() > 1
function g(f)
pmap(1:5) do x
f(x)
end
end
addone(x) = x+1
subone(x) = x-1
g(addone)
g(subone)
This, of course, did not work and resulted in.
On worker 2:
UndefVarError: `#addone` not defined
Next I tried passing the function f as an argument of pmap
@assert nprocs() > 1
function g(f)
pmap(zip(1:5, Iterators.repeated(f))) do (x,f)
f(x)
end
end
addone(x) = x+1
subone(x) = x-1
g(addone)
g(subone)
This also did not work, it also threw
On worker 2:
UndefVarError: `#addone` not defined
Now I am at a loss, surely something like this must be possible in Julia.
@BatWannBee is totally right that you should not do it and should use just @everywhere
.
However if you want to do it here is the code snippet.
Firstly, we perfom a set up
using Distributed
addprocs(2)
@everywhere using Serialization
addone(x::Int) = x+1 + 100myid()
Now we move the function to the other workers
# the name of the function to be moved around
fname = :addone
# Serializing methods of the function fname to a buffer
buf = IOBuffer()
serialize(buf, methods(eval(fname)))
# Deserializing the function on remote workers
# Note that there are two steps
# 1. creating an empty function
# 2. providing methods
Distributed.remotecall_eval(Main, workers(), quote
function $fname end
deserialize(seekstart($buf))
end)
Now we can test what we did:
julia> fetch(@spawnat 3 methods(addone))
# 1 method for generic function "addone" from Main:
[1] addone(x::Int64)
@ REPL[3]:1
julia> fetch(@spawnat 3 addone(4))
305