我是Erlang新手,所以请对我宽容一点。
我对如何在erlang中执行receive语句感到困惑,例如:
loop() ->
receive
MessageA -> handlerA();
MessageB -> handlerB()
end
如果接收到MessageA,并执行了handlerA,过了一段时间,MessageB在进程的收件箱中收到,handlerB是否被执行?
我猜不是,因为我看到很多代码递归地再次执行receive语句:
loop() ->
receive
MessageA ->
handlerA(),
loop();
MessageB ->
handlerB(),
loop()
end
但是这里有一个问题,如果messageA的处理程序包含另一个这样的接收语句:
loop() ->
receive
MessageA ->
loop2(),
MessageB ->
handlerB(),
loop()
end
loop2() ->
receive
MessageC ->
handlerC()
loop2()
MessageD ->
handlerD()
loop2()
end
在这种情况下,这是否意味着如果我进入MessageA的处理程序,我永远不能处理MessageB?
我该如何解决这个问题?通过将MessageB的处理程序放入loop2?这看起来不是很优雅,特别是当有多个级别的receive语句时。
有更好的方法吗?
下面的代码意味着"执行接收单个消息",所以如果您想接收多个消息,则需要循环。在Erlang中,典型的方法是自己尾部调用。
loop() ->
receive
MessageA -> handlerA();
MessageB -> handlerB()
end
在上一个示例中,看起来您有某种状态机,其中A更改为另一种状态,而B保持相同的状态。当您处于期望接收C和D消息的状态时,不能再接收a消息不一定是问题,但这取决于问题域。
你说对了。
关于loop和loop2的示例,这样的实现意味着您希望在接收到messageA时选择一些新行为,并且如果稍后出现messageB,则应该丢弃它。(注意,如果您使用带有大写字母的MessageA,它将成为一个变量名,并且它将匹配任何消息!)。在这种情况下,这是有意义的,您应该添加一个垃圾消息子句来从队列messageB和其他意外消息中删除:
loop2() ->
receive
messageC ->
handlerC(),
loop2();
messageD ->
handlerD(),
loop2();
_ ->
loop2()
end.
另一种可能性是您实现了一种状态机,那么您应该使用OTP行为gen_fsm。
如果不是这种情况,这意味着您仍然希望捕获稍后到来的消息,我强烈建议您保持单个循环,并在单个receive语句中处理所有可能的消息。