如何理解 Erlang 的接收语句?



我是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语句中处理所有可能的消息。

相关内容

  • 没有找到相关文章

最新更新