-
Notifications
You must be signed in to change notification settings - Fork 14
Description
I am trying to run some parallel code defined inside a module via include_string
, and I can't quite figure out how it works or how it's supposed to work.
It seems like a bug for such a simple case to not work, so I'm making an issue here. But it may be something that can't be fixed with Julia's current module system.
Main question: Is there a way to use a sandbox module without breaking Distributed.jl?
Short failing code
A simple remote call works when run in module Main:
using Distributed
worker_ids = addprocs(2)
remotecall_wait(() -> println("I want to run this remotely"), 2)
But doesn't work when in a different module:
module sandbox
using Distributed
worker_ids = addprocs(2)
remotecall_wait(() -> println("I want to run this remotely"), 2)
end
ERROR: On worker 2:
UndefVarError: sandbox not defined
Stacktrace:
[1] deserialize_module
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:996
[2] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:895
[3] deserialize
Test scripts
I made a test script to figure out how to work with this. I run the script in a sandbox module and in the Main module.
Driver script mfe_driver.jl
.
filename = ARGS[1]
include_string(Module(:sandbox_mod), read(filename, String), filename)
Escape-to-main method: mfe.jl
.
The second is a script that escapes the sandbox module to get the function to run remotely: mfe.jl
.
mfe.jl
using Distributed
worker_ids = addprocs(2)
try
println("================== Main process - try to run remotely")
try
remotecall_wait(() -> println("I want to run this remotely"), 2)
catch e
showerror(stdout, e)
end
println()
println()
println("================== Main process - define and run function locally")
function I_want_to_run_this_remotely()
println("I want to run this remotely")
end
I_want_to_run_this_remotely()
println()
println()
println("================== Main process - run remotely")
try
remotecall_wait(I_want_to_run_this_remotely, 2)
catch e
showerror(stdout, e)
end
println()
println()
println("================== Main process - define function in local Main and run locally")
@everywhere [1] begin
using Distributed
println(" process $(myid()) has module $(@__MODULE__)")
function I_want_to_run_this_remotely()
println("I want to run this remotely")
end
end
Main.I_want_to_run_this_remotely()
println()
println()
println("================== Main process - run remotely")
try
remotecall_wait(Main.I_want_to_run_this_remotely, 2)
catch e
showerror(stdout, e)
end
println()
println()
println("================== Main process - define function in everyone's Main")
@everywhere begin
using Distributed
println(" process $(myid()) has module $(@__MODULE__)")
function I_want_to_run_this_remotely()
println("I want to run this remotely")
end
end
println()
println()
println("================== Main process - run remotely")
try
remotecall_wait(Main.I_want_to_run_this_remotely, 2)
catch e
showerror(stdout, e)
end
finally
rmprocs(worker_ids)
end
- In the non-sandboxed case,
remoteprocess_call
works as expected. - The only case that fails is when the function is defined on the driver process using
@everywhere
. And I don't understand how that is different from defining the function on the driver process without@everywhere
.
Output of "julia mfe.jl"
================== Main process - try to run remotely
From worker 2: I want to run this remotely
================== Main process - define and run function locally
I want to run this remotely
================== Main process - run remotely
From worker 2: I want to run this remotely
================== Main process - define function in local Main and run locally
process 1 has module Main
I want to run this remotely
================== Main process - run remotely
On worker 2:
UndefVarError: #I_want_to_run_this_remotely not defined
Stacktrace:
[1] deserialize_datatype
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:1364
[2] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:866
[3] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[4] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:873
[5] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813 [inlined]
[6] deserialize_msg
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/messages.jl:87
[7] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[8] invokelatest
@ ./essentials.jl:726 [inlined]
[9] message_handler_loop
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:176
[10] process_tcp_streams
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:133
[11] #103
@ ./task.jl:484
================== Main process - define function in everyone's Main
process 1 has module Main
From worker 2: process 2 has module Main
From worker 3: process 3 has module Main
================== Main process - run remotely
From worker 2: I want to run this remotely
- In the sandboxed case, the
remotecall_wait
works only if the function is defined in Main for each process.
Output of "julia mfe_driver.jl mfe.jl"
================== Main process - try to run remotely
On worker 2:
UndefVarError: sandbox_mod not defined
Stacktrace:
[1] deserialize_module
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:996
[2] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:895
[3] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[4] deserialize_datatype
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:1363
[5] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:866
[6] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[7] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:873
[8] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813 [inlined]
[9] deserialize_msg
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/messages.jl:87
[10] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[11] invokelatest
@ ./essentials.jl:726 [inlined]
[12] message_handler_loop
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:176
[13] process_tcp_streams
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:133
[14] #103
@ ./task.jl:484
================== Main process - define and run function locally
I want to run this remotely
================== Main process - run remotely
On worker 2:
UndefVarError: sandbox_mod not defined
Stacktrace:
[1] deserialize_module
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:996
[2] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:895
[3] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[4] deserialize_datatype
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:1363
[5] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:866
[6] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[7] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:873
[8] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813 [inlined]
[9] deserialize_msg
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/messages.jl:87
[10] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[11] invokelatest
@ ./essentials.jl:726 [inlined]
[12] message_handler_loop
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:176
[13] process_tcp_streams
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:133
[14] #103
@ ./task.jl:484
================== Main process - define function in local Main and run locally
process 1 has module Main
I want to run this remotely
================== Main process - run remotely
On worker 2:
UndefVarError: #I_want_to_run_this_remotely not defined
Stacktrace:
[1] deserialize_datatype
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:1364
[2] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:866
[3] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[4] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:873
[5] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813 [inlined]
[6] deserialize_msg
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/messages.jl:87
[7] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[8] invokelatest
@ ./essentials.jl:726 [inlined]
[9] message_handler_loop
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:176
[10] process_tcp_streams
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:133
[11] #103
@ ./task.jl:484
================== Main process - define function in everyone's Main
process 1 has module Main
From worker 3: process 3 has module Main
From worker 2: process 2 has module Main
================== Main process - run remotely
From worker 2: I want to run this remotely
Define-sandbox-everywhere method: mfe_define_module.jl
I don't want to escape the sandbox to define things in the Main scope, so I tried to work within the sandbox.
This file tries to define the sandbox module for the worker processes.
mfe_define_module.jl
using Distributed
worker_ids = addprocs(2)
try
println("================== Main process - determine current module information")
current_module_local = split(string(@__MODULE__), ".")[end]
println(" Driver module: $(@__MODULE__)")
println(" Driver module string: $current_module_local")
println()
println()
println("================== Main process - define module in workers")
@everywhere worker_ids begin
using Distributed
driver_module = try
Module(Symbol(Meta.parse($current_module_local)))
catch e
showerror(stdout, e)
end
println("Process $(myid()): ", driver_module, " ", typeof(driver_module))
end
println()
println()
driver_module = @__MODULE__
println("================== Main process - import module in workers")
try
@everywhere worker_ids begin
println("Process $(myid()): ", driver_module, " ", typeof(driver_module))
end
catch e
showerror(stdout, e)
end
println()
println()
println("================== Main process - try to run remotely")
try
remotecall_wait(() -> println("I want to run this remotely"), 2)
catch e
showerror(stdout, e)
end
println()
println()
println("================== Main process - define and run function locally")
function I_want_to_run_this_remotely()
println("I want to run this remotely")
end
I_want_to_run_this_remotely()
println()
println()
println("================== Main process - run remotely")
try
remotecall_wait(I_want_to_run_this_remotely, 2)
catch e
showerror(stdout, e)
end
finally
rmprocs(worker_ids)
end
- It successfully defines a module of the same name in the worker processes, but it is still not possible to call functions with
remotecall_wait
.
Output of "julia mfe_driver.jl mfe_define_module.jl"
================== Main process - determine current module information
Driver module: Main.sandbox_mod
Driver module string: sandbox_mod
================== Main process - define module in workers
From worker 2: Process 2: Main.sandbox_mod Module
From worker 3: Process 3: Main.sandbox_mod Module
================== Main process - import module in workers
From worker 2: Process 2: Main.sandbox_mod Module
From worker 3: Process 3: Main.sandbox_mod Module
================== Main process - try to run remotely
On worker 2:
UndefVarError: sandbox_mod not defined
Stacktrace:
[1] deserialize_module
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:996
[2] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:895
[3] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[4] deserialize_datatype
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:1363
[5] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:866
[6] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[7] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:873
[8] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813 [inlined]
[9] deserialize_msg
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/messages.jl:87
[10] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[11] invokelatest
@ ./essentials.jl:726 [inlined]
[12] message_handler_loop
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:176
[13] process_tcp_streams
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:133
[14] #103
@ ./task.jl:484
================== Main process - define and run function locally
I want to run this remotely
================== Main process - run remotely
On worker 2:
UndefVarError: sandbox_mod not defined
Stacktrace:
[1] deserialize_module
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:996
[2] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:895
[3] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[4] deserialize_datatype
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:1363
[5] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:866
[6] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813
[7] handle_deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:873
[8] deserialize
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Serialization/src/Serialization.jl:813 [inlined]
[9] deserialize_msg
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/messages.jl:87
[10] #invokelatest#2
@ ./essentials.jl:729 [inlined]
[11] invokelatest
@ ./essentials.jl:726 [inlined]
[12] message_handler_loop
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:176
[13] process_tcp_streams
@ ~/.julia/juliaup/julia-1.8.5+0.x64.linux.gnu/share/julia/stdlib/v1.8/Distributed/src/process_messages.jl:133
[14] #103
@ ./task.jl:484
Version info
I tested this with Julia installed by juliaup version 1.13.0, with Julia versions below.
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 8 × Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-13.0.1 (ORCJIT, skylake)
Threads: 1 on 8 virtual cores
and
Julia Version 1.11.0-rc1
Commit 3a35aec36d1 (2024-06-25 10:23 UTC)
Build Info:
Official https://julialang.org/ release
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 8 × Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
WORD_SIZE: 64
LLVM: libLLVM-16.0.6 (ORCJIT, skylake)
Threads: 1 default, 0 interactive, 1 GC (on 8 virtual cores)