Notas de computación paralela de Julia (3)

Cinco, llamada remota dos

Esta sección habla de tres comandos de macro que son convenientes para llamadas remotas.

Comando macro@everywhere

Un caso especial de llamadas remotas es hacer que la declaración / función / expresión se ejecute en todos los procesos. Por ejemplo: abra 1 trabajador y luego declare una variable en cada proceso (proceso principal + 1 trabajador) betay calcule una expresión beta+1. Usando el método descrito anteriormente, se puede escribir como:

julia> for pid = 1:2
           r = @fetchfrom pid (beta=0;beta+1)
           println(r)
       end
1
1

Se utiliza println()para imprimir los resultados, porque el REPL predeterminado para imprimir los resultados de la última línea, y en este ejemplo, la última línea es end, y no se muestran resultados. Recordatorio especial: use paréntesis cuando llame a varias expresiones de forma remota; de lo contrario, solo se llamará a la última, lo que dará como resultado betaindefinido, como este:

julia> for pid = 1:2
           r = @fetchfrom pid beta=0;beta+1
           println(r)
       end
ERROR: UndefVarError: beta not defined

¿Se puede hacer en un solo paso? ¡Tener! Eso es todo @everywhere. Puede abreviarse como:

julia> @everywhere (beta=0;beta+1)

Es una transmisión de una expresión, que se ejecutará en todos los procesos. Pero no devuelve un objeto Future, y el resultado no es visible, por lo que generalmente se usa para declaraciones de transmisión, y las expresiones subsiguientes aún usan @fetchllamadas remotas como "comandos mono" para devolver los resultados. Por supuesto, podemos hacer un pequeño truco, @everywheredifundir algunas expresiones que no necesitan devolver resultados y que son compartidas por todos los procesos , y luego solo usar el "comando único" para obtener los resultados de las expresiones que deben devolver el resultado al final. Será más conciso escribir de esta manera.

Comando macro@eval

@evalLos comandos se utilizan para realizar "sustitución de valor" en expresiones. La denominada "sustitución de valor" aquí significa evaluar primero la expresión y luego reemplazar la posición de la expresión con el valor. También es posible "sustitución de valores" para una sola variable en la expresión, simplemente agregue un $símbolo antes de la variable . Dado que este comando tiene una alta prioridad, podemos usarlo para realizar algunas operaciones sao, como usar variables locales en Worker:

julia> beta = 0;

julia> @eval @everywhere $beta+1

Que entra en vigor antes @evalque @everywhere, betareemplaza con 1, por lo que @everywhereno se informará ningún error. Para demostrar que la @evalprioridad es realmente mayor, puede intentar:

julia> p = 0;  @fetch @eval $p+1
1
# 或者
julia> p = 0;  @everywhere @eval $p+1

Se puede ver que @evalla parte delantera y trasera son iguales.

A modo de comparación, echemos un vistazo al informe de errores:

julia>  kappa = 0; @everywhere kappa+1
ERROR: On worker 2:
UndefVarError: kappa not defined

Tenga cuidado de no usarlo aquí beta, porque lo anterior ya se ha betadifundido, por lo que ya hay betadeclaraciones en cada proceso .

Comando macro@distributed

Permítanme hablar sobre un comando macro específicamente para el bucle for @distributed. Su uso es

@distributed (聚合函数) for var = range
					       表达式
					   end

Si hay varias expresiones, el valor de la última expresión participa en la agregación. La función de agregación es un parámetro opcional, si está vacía, significa que no hay agregación. P.ej:

julia> s = @distributed (+) for i = 1:10
                               2*i
                               3*i
                            end
165

Se puede ver que agrega los resultados de la última fila. Si no escribe una función agregada, el valor devuelto ya no es un valor. En una sola computadora, el @distributedparalelismo a nivel de corrutina se usará primero, por lo que se devuelve una tarea, de la siguiente manera:

julia> s = @distributed  for i = 1:10
                               2*i
                               3*i
                            end
Task (queued) @0x00000000079d99f0

Tenga en cuenta que la tarea está en la cola, porque regresa inmediatamente cuando se crea. Ya sea que escriba funciones agregadas o no, el programador de Julia siempre lo programará automáticamente para que se ejecute en el momento adecuado. Podemos comprobar su ejecución en cualquier momento:

julia> istaskdone(s)
true

En cuanto a cómo especificar el @distributedparalelismo a nivel de proceso y si el paralelismo a nivel de proceso @distributedse utilizará primero en un grupo de computadoras , el libro no está escrito con claridad y debe ser probado.

Seis, referencia remota

Todas las llamadas remotas mencionadas anteriormente se basan en la transferencia de datos entre procesos, es decir, los datos de cada proceso están aislados entre sí y la cooperación se realiza mediante referencias remotas. Una referencia remota es un objeto, dividido en objetos Future y objetos RemoteChannel. El primero está referenciado desde un trabajador al proceso principal, y el último se crea y almacena en un trabajador y es visible para todos los procesos.

Regala una castaña para ilustrar:

julia> c = Channel(2)
Channel{Any}(sz_max:2,sz_curr:0)

julia> @fetchfrom 2 put!(c,10)
10

julia> isready(c)
false

julia> @fetchfrom 2 isready(c)
true

Este tipo de referencia remota se implementa utilizando objetos Future. Como se muestra en la figura, cuando cse crea el proceso principal (rojo) como un parámetro de llamada remota, se crea una copia (verde) en el Trabajador, se ejecuta la expresión para obtener el resultado (azul), y el resultado se extrae y almacena en el Futuro del proceso principal (Entonces este Futuro en realidad cno tiene nada que ver con lo local ). La operación en el trabajador solo cambia el estado de la copia sin afectar el proceso principal.
Inserte la descripción de la imagen aquí
Tenga en cuenta que el resultado @fetchfromde la expresión put!(c,10)(azul) se extrae , por lo que el resultado (azul) se eliminará del Worker, pero cla copia (verde) como parámetro no se eliminará y todavía existe en el Worker, por lo que puede Continúe utilizándolo en el control remoto.

Si queremos cmodificar el Worker desde el proceso principal en cualquier momento durante la operación del par Worker c, entonces las referencias remotas basadas en Future mencionadas anteriormente no funcionarán. Con este fin, Julia proporciona uno RemoteChannel. Un ejemplo del método de creación es el siguiente:

julia> f = ()->Channel{Int}(10)
#47 (generic function with 1 method)

julia> r = RemoteChannel(f,2)
RemoteChannel{Channel{Int64}}(2, 1, 45)

El primer paso es declarar una función f(ver la sintaxis de funciones anónimas), que debe devolver un canal. El segundo paso RemoteChannel(f, 2)es crear un RemoteChannel en el Worker con PID = 2 y tener flos mismos atributos que el Channel devuelto. Por supuesto, escribir de esta manera dejará un proceso principal redundante f, por lo que dos oraciones se escriben en una oración en el libro:

julia> r = RemoteChannel(()->Channel{Int}(10),2)
RemoteChannel{Channel{Int64}}(2, 1, 47)

rEs el identificador de este RemoteChannel, ubicado en el proceso principal. Podemos rmodificar el RemoteChannel mediante operaciones , como un dron de control remoto. Por ejemplo isready(r), put!(r,100)etc. también incluyen extracción fetch(r)y take!(r). Además, podemos pasarlo como parámetro a cualquier Worker y luego operar allí, por ejemplo:

julia> @fetchfrom 3 put!(r,100)
RemoteChannel{Channel{Int64}}(2, 1, 47)

julia> take!(r)
100

julia> isready(r)
false

Aquí rponemos un elemento en el Worker con PID = 3 , y luego lo extraemos en el proceso principal, y finalmente comprobamos que restá vacío en el proceso principal , y se puede ver que restá compartido.

Si no se especifica ningún PID al crear un RemoteChannel, se creará en el proceso principal de forma predeterminada. No importa dónde se cree, las operaciones en el identificador harán que los datos pasen entre el "proceso de operación" y el "proceso de creación". Si los datos son grandes, esta transferencia consumirá mucho tiempo. El concepto de "matriz compartida" se presenta a continuación para resolver este problema.

Supongo que te gusta

Origin blog.csdn.net/iamzhtr/article/details/91359782
Recomendado
Clasificación