parallel-processing julia-lang julia

parallel processing - Julia: cómo copiar datos a otro procesador en Julia



parallel-processing julia-lang (4)

¿Cómo se mueven los datos de un procesador a otro en julia?

Digamos que tengo una matriz

a = [1:10]

O alguna otra estructura de datos. ¿Cuál es la forma correcta de colocarlo en todos los demás procesadores disponibles para que esté disponible en esos procesadores con el mismo nombre de variable?


Al principio no sabía cómo hacer esto, así que pasé un tiempo descubriéndolo.

Aquí hay algunas funciones que escribí para pasar objetos:

sendto

Enviar un número arbitrario de variables a procesos específicos.

Se crean nuevas variables en el módulo Principal en procesos especificados. El nombre será la clave del argumento de la palabra clave y el valor será el valor asociado.

function sendto(p::Int; args...) for (nm, val) in args @spawnat(p, eval(Main, Expr(:(=), nm, val))) end end function sendto(ps::Vector{Int}; args...) for p in ps sendto(p; args...) end end

Ejemplos

# creates an integer x and Matrix y on processes 1 and 2 sendto([1, 2], x=100, y=rand(2, 3)) # create a variable here, then send it everywhere else z = randn(10, 10); sendto(workers(), z=z)

getfrom

Recupere un objeto definido en un módulo arbitrario en un proceso arbitrario. El valor predeterminado es el módulo principal.

El nombre del objeto a recuperar debe ser un símbolo.

getfrom(p::Int, nm::Symbol; mod=Main) = fetch(@spawnat(p, getfield(mod, nm)))

Ejemplos

# get an object from named x from Main module on process 2. Name it x x = getfrom(2, :x)

passobj

Pase un número arbitrario de objetos de un proceso a procesos arbitrarios. La variable debe definirse en el módulo from_mod del proceso src y se copiará con el mismo nombre al módulo to_mod en cada proceso de destino.

function passobj(src::Int, target::Vector{Int}, nm::Symbol; from_mod=Main, to_mod=Main) r = RemoteRef(src) @spawnat(src, put!(r, getfield(from_mod, nm))) for to in target @spawnat(to, eval(to_mod, Expr(:(=), nm, fetch(r)))) end nothing end function passobj(src::Int, target::Int, nm::Symbol; from_mod=Main, to_mod=Main) passobj(src, [target], nm; from_mod=from_mod, to_mod=to_mod) end function passobj(src::Int, target, nms::Vector{Symbol}; from_mod=Main, to_mod=Main) for nm in nms passobj(src, target, nm; from_mod=from_mod, to_mod=to_mod) end end

Ejemplos

# pass variable named x from process 2 to all other processes passobj(2, filter(x->x!=2, procs()), :x) # pass variables t, u, v from process 3 to process 1 passobj(3, 1, [:t, :u, :v]) # Pass a variable from the `Foo` module on process 1 to Main on workers passobj(1, workers(), [:foo]; from_mod=Foo)


Para complementar la respuesta de @ spencerlyon2, aquí hay algunas macros:

function sendtosimple(p::Int, nm, val) ref = @spawnat(p, eval(Main, Expr(:(=), nm, val))) end macro sendto(p, nm, val) return :( sendtosimple($p, $nm, $val) ) end macro broadcast(nm, val) quote @sync for p in workers() @async sendtosimple(p, $nm, $val) end end end

La macro @spawnat vincula un valor a un símbolo en un proceso particular

julia> @sendto 2 :bip pi/3 RemoteRef{Channel{Any}}(9,1,5340) julia> @fetchfrom 2 bip 1.0471975511965976

La macro @broadcast vincula un valor a un símbolo en todos los procesos excepto 1 (como descubrí, las expresiones futuras que usan el nombre copian la versión del proceso 1 )

julia> @broadcast :bozo 5 julia> @fetchfrom 2 bozo 5 julia> bozo ERROR: UndefVarError: bozo not defined julia> bozo = 3 #these three lines are why I exclude pid 1 3 julia> @fetchfrom 7 bozo 3 julia> @fetchfrom 7 Main.bozo 5


Para que todos lo sepan, puse estas ideas juntas en un paquete ParallelDataTransfer.jl para esto. Entonces solo tienes que hacer

using ParallelDataTransfer

(después de la instalación) para usar las funciones mencionadas en las respuestas aquí. ¿Por qué? ¡Estas funciones son bastante útiles! Agregué algunas pruebas, algunas macros nuevas y las actualicé un poco (pasan la v0.5, fallan en la v0.4.x). Siéntase libre de enviar solicitudes de extracción para editarlas y agregar más.


use @eval @everywhere... y escape de la variable local. Me gusta esto:

julia> a=collect(1:3) 3-element Array{Int64,1}: 1 2 3 julia> addprocs(1) 1-element Array{Int64,1}: 2 julia> @eval @everywhere a=$a julia> @fetchfrom 2 a 3-element Array{Int64,1}: 1 2 3