+1 à rvirding, "C'est une aide énorme lors de la construction de systèmes concurrents" est exactement ce dont il s'agit. Cela m'a rappelé un exemple de code - une solution au "Smokers Problem" - que j'ai créé il y a quelque temps. J'ai pensé que le partager pourrait aider à illustrer le propos :
-module(smokers).
-export([smokers/0]).
smokers() ->
Rounds = 1000000,
Agent = self(),
lists:foreach(fun(Material) -> spawn(fun() -> startSmoker(Agent, Material) end) end, materials()),
done = agent(Rounds),
io:format("Done ~p rounds~n", [Rounds]).
agent(0) ->
done;
agent(Rounds) ->
offer(twoRandomMaterials(), Rounds).
offer(AvailableMaterials, Rounds) ->
receive
{take, Smoker, AvailableMaterials} ->
Smoker ! smoke,
receive
doneSmoking ->
agent(Rounds - 1)
end
end.
startSmoker(Agent, Material) ->
smoker(Agent, lists:delete(Material, materials())).
smoker(Agent, Missing) ->
Agent ! {take, self(), Missing},
receive
smoke ->
Agent ! doneSmoking,
smoker(Agent, Missing)
end.
twoRandomMaterials() ->
Materials = materials(),
deleteAt(random:uniform(length(Materials)) - 1, Materials).
materials() ->
[paper, tobacco, match].
deleteAt(_, []) -> [];
deleteAt(0, [_ | T]) -> T;
deleteAt(Idx, [H | T]) -> [H | deleteAt(Idx - 1, T)].
Ce qui est intéressant ici, c'est qu'il y a potentiellement trois messages dans la file d'attente lorsque nous essayons la fonction receive {take, Smoker, AvailableMaterials}
. Seulement un d'entre eux peuvent toutefois être traités maintenant . Ensuite, il y a l'intérieur receive doneSmoking
comme une poignée de main. Ainsi, pour l'un, la sélection des messages appropriés qui permet au code de faire un travail tout en ne perdant pas l'autre take
lors de la réception du message de poignée de main est ce qui résout tous les problèmes de concurrence ici. Si les messages non conformes/non traitables étaient abandonnés à un moment donné, la smoker
resteraient bloqués pour toujours (à moins qu'ils ne répètent périodiquement leurs demandes).