如何理解Erlang的receive语句?

How to understand Erlang's receive statement?

我是 Erlang 的新手,所以请放轻松。

我对在 erlang 中如何执行 receive 语句感到困惑,例如:

loop() ->
   receive
       MessageA -> handlerA();
       MessageB -> handlerB()
   end

如果收到 MessageA 并执行 handlerA,一段时间后,在进程的收件箱中收到 MessageB,是否执行 handlerB?

我猜不是,因为我看到很多代码递归再次执行接收语句:

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?这看起来不太优雅,尤其是当有多个级别的接收语句时。

有更好的方法吗?

下面代码的意思是"execute receiving a single message",所以如果要接收多个,需要循环。在 Erlang 中执行此操作的典型方法是尾部调用自己。

loop() ->
   receive
       MessageA -> handlerA();
       MessageB -> handlerB()
   end

在您的最后一个示例中,您似乎拥有某种状态机,其中 A 更改为另一个状态,而 B 保持相同状态。当您处于预期 C 和 D 消息的状态时,您不能再收到 A 消息不一定是问题,但这取决于问题域。

你明白了。

关于循环和循环 2 的示例,这样的实现意味着您希望在收到 messageA 时 select 一些新行为,如果稍后出现 messageB,则应丢弃它。 (请注意,如果您将 MessageA 与大写字母一起使用,它将成为一个变量名称,并且它将匹配任何消息!)。在这种情况下这是有道理的,您应该添加一个垃圾消息子句以从队列中删除 messageB 和其他意外消息:

loop2() ->
   receive
      messageC ->
          handlerC(),
          loop2();
      messageD ->
          handlerD(),
          loop2();
      _ ->
          loop2()
   end.

另一种可能性是您实现了一种状态机,那么您应该使用 OTP 行为 gen_fsm。

如果不是这种情况,这意味着您仍想捕获稍后发送的消息 B,我强烈建议您保持单个循环并在单个接收语句中处理所有可能的消息。