Как понять утверждение получения Эрланга?

Я новичок в 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, я никогда не смогу обработать MessageB?

И как я могу решить это? Поместив обработчик MessageB в loop2? Это выглядит не очень изящно, особенно когда есть несколько уровней операторов приема.

Есть лучший способ сделать это?

2 ответа

Решение

Следующий код означает "выполнить получение одного сообщения", поэтому, если вы хотите получить более одного, вам нужно выполнить цикл. Типичный способ сделать это в Erlang - это самозванец.

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

В последнем примере похоже, что у вас есть какой-то конечный автомат, где A переходит в другое состояние, а B остается в том же состоянии. Не обязательно проблема в том, что вы больше не можете получать сообщения A, когда вы находитесь в состоянии, в котором вы ожидаете сообщения C и D, но это будет зависеть от проблемной области.

Ты понял.

Что касается вашего примера с loop и loop2, такая реализация означает, что вы хотите выбрать новое поведение при получении messageA, и вам следует отказаться от messageB, если оно придет позже. (имейте в виду, что если вы используете MessageA с заглавной буквой, оно становится именем переменной и будет соответствовать любому сообщению!). В этом случае это имеет смысл, и вы должны добавить предложение мусорного сообщения, чтобы удалить из очереди messageB и другие неожиданные сообщения:

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

Другая возможность заключается в том, что вы реализуете некий конечный автомат, тогда вам следует использовать поведение OTP gen_fsm.

Если это не так, то есть вы все еще хотите перехватить сообщение B, приходящее позже, я настоятельно рекомендую вам сохранить один цикл и позаботиться обо всех возможных сообщениях в одном операторе приема.

Другие вопросы по тегам