+1 到 rvirding,“在构建并发系统时它是一个巨大的帮助”,这正是它的意义所在。让我想起了一些示例代码——“吸烟者问题”解决方案——我不久前就开始了。我认为分享它可能有助于说明这一点:
-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)].
这里有趣的是,当我们尝试receive {take, Smoker, AvailableMaterials} 时,队列中可能有三条消息。但是,现在只能处理其中的一个。然后是内部receive doneSmoking 作为握手。因此,对于一个选择正确的消息,允许代码完成一些工作以及在接收握手消息时不丢失其他 take 消息是解决所有并发问题的方法。如果不匹配/不可处理的消息在任何时候丢弃,smokers 将永远卡住(除非他们会定期重复他们的请求)。