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