Permite caminar a través del código:
-module(ring).
-export([start/2, node/2]).
El nombre node
es uno evito porque un nodo() en Erlang tiene la connotación de un Erlang máquina virtual que se ejecuta en una máquina - por lo general varios nodos ejecutan en varias máquinas . Prefiero llamarlo ring_proc
o algo similar.
node(NodeNumber, NumberOfNodes) ->
NextNodeNumber = (NodeNumber + 1) rem NumberOfNodes,
NextNodeName = node_name(NextNodeNumber),
Esto es lo que estamos tratando de desovar, y se obtiene un número al siguiente nodo y el nombre del siguiente nodo. Veamos node_name/1
como un interludio:
node_name(NodeNumber) ->
list_to_atom(lists:flatten(io_lib:format("node~w", [NodeNumber]))).
Esta función es una mala idea. Necesitará un nombre local que necesite ser un átomo, por lo que creó una función que puede crear tales nombres arbitrarios. La advertencia aquí es que la tabla de átomos no es basura recolectada y limitada, por lo que debemos evitarla si es posible. El truco para resolver este problema es pasar los pids en su lugar y construir el anillo en reversa. El proceso final será luego atar el nudo del anillo:
mk_ring(N) ->
Pid = spawn(fun() -> ring(none) end),
mk_ring(N, Pid, Pid).
mk_ring(0, NextPid, Initiator) ->
Initiator ! {set_next, NextPid},
Initiator;
mk_ring(N, NextPid, Initiator) ->
Pid = spawn(fun() -> ring(NextPid) end),
mk_ring(N-1, Pid, Initiator).
y luego podemos reescribir su función de arranque:
start(NumberOfNodes, NumberOfCircuits) ->
RingStart = mk_ring(NumberOfNodes)
RingStart ! {operate, NumberOfCircuits, self()},
receive
done ->
RingStart ! stop
end,
ok.
El código anillo es entonces algo a lo largo de las líneas de:
ring(NextPid) ->
receive
{set_next, Pid} ->
ring(Pid);
{operate, N, Who} ->
ring_ping(N, NextPid),
Who ! done,
ring(NextPid);
ping ->
NextPid ! ping,
ring(NextPid);
stop ->
NextPid ! stop,
ok
end.
Y al fuego algo alrededor del anillo N veces:
ring_ping(0, _Next) -> ok;
ring_ping(N, Next) ->
Next ! ping
receive
ping ->
ring_ping(N-1, Next)
end.
(Ninguno de estos códigos ha sido probado por cierto, por lo que puede ser bastante erróneo).
En cuanto al resto de su código:
receive
CircuitNumber ->
io:format("Node ~p Circuit ~p~n", [NodeNumber, CircuitNumber]),
Me marcar los CircuitNumber
con algún átomo: {run, CN}
.
LastNode = NodeNumber =:= NumberOfNodes - 1,
NextCircuitNumber = case LastNode of
true ->
CircuitNumber - 1;
false ->
CircuitNumber
end,
Esto se puede hacer con un if:
NextCN = if NodeNumber =:= NumberOfNodes - 1 -> CN -1;
NodeNumber =/= NumberOfNodes - 1 -> CN
end,
La siguiente parte aquí:
if
NextCircuitNumber > 0 ->
NextNodeName ! NextCircuitNumber;
true ->
ok
end,
if
CircuitNumber > 1 ->
node(NodeNumber, NumberOfNodes);
true ->
ok
end
necesita el caso true
, a menos que nunca lo golpeó. El proceso se bloqueará si no coincide nada en el if
. A menudo es posible volver a cablear el código para no confiar tanto en las construcciones de conteo, como el código anterior de pistas de minas.
Se pueden evitar varios problemas con este código. Un problema con el código actual es que si algo se bloquea en el anillo, se rompe. Podemos usar spawn_link
en lugar de spawn
para unir el anillo, por lo que dichos errores destruirán todo el anillo. Además, nuestra función ring_ping
se bloqueará si se envía un mensaje mientras el anillo está funcionando. Esto puede ser aliviado, la forma más simple es probablemente alterar el estado del proceso de anillo de modo que sepa que está funcionando actualmente y doblar ring_ping
en ring
. Finalmente, probablemente también deberíamos vincular el engendro inicial para que no terminemos con un anillo grande que esté en vivo pero que nadie tenga referencia. Tal vez podríamos registrar el proceso inicial por lo que es fácil agarrar el anillo más tarde.
La función start
también es mala de dos maneras. En primer lugar, debemos usar make_ref()
para etiquetar un mensaje único y recibir la etiqueta, por lo que otro proceso no puede ser siniestro y simplemente envíe done
al proceso de inicio mientras el anillo funciona. Probablemente también deberíamos agregar un monitor en el anillo, mientras está funcionando. De lo contrario, nunca se nos informará, se debe bloquear el anillo mientras esperamos el mensaje done
(con etiqueta). OTP hace ambas cosas en sus llamadas sincrónicas por cierto.
Finalmente, por último: No, usted no tiene que limpiar un registro.
¡buenos comentarios aquí! –