【问题标题】:How to understand Erlang's receive statement?如何理解 Erlang 的接收语句?
【发布时间】:2015-09-02 08:43:19
【问题描述】:

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

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

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的hander,就永远不能处理MessageB了?

我该如何解决这个问题?通过将 MessageB 的处理程序放入 loop2?这看起来不太优雅,尤其是当有多个级别的接收语句时。

有没有更好的方法来做到这一点?

【问题讨论】:

    标签: erlang receiver message-handlers


    【解决方案1】:

    以下代码的意思是“执行接收单条消息”,所以如果要接收多条消息,需要循环。在 Erlang 中执行此操作的典型方式是尾调用自己。

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

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

    【讨论】:

    • 谢谢!如果我在处理 C 和 D 时仍然期待 B 消息怎么办?我是否在loop2中重复handlerB?这循环非常冗长。
    【解决方案2】:

    你明白了。

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

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

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

    如果不是这样,这意味着您仍然想捕获稍后出现的消息 B,我强烈建议您保留一个循环并在单个接收语句中处理所有可能的消息。

    【讨论】:

      猜你喜欢
      • 2010-11-24
      • 2019-12-25
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 2021-12-31
      • 2012-06-24
      • 2013-01-22
      • 1970-01-01
      相关资源
      最近更新 更多