Как понять оператор получения Erlang?

Я новичок в Erlang, поэтому, пожалуйста, будьте со мной полегче.

Я смущен тем, как оператор получения выполняется в erlang, например:

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

Если получено MessageA и выполняется обработчик A, через некоторое время в папку «Входящие» процесса поступает MessageB, выполняется ли обработчик B?

Я думаю, что нет, так как я вижу много кода, который рекурсивно выполняет оператор получения снова:

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? Это выглядит не очень изящно, особенно при наличии нескольких уровней операторов получения.

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


person NeoWang    schedule 02.09.2015    source источник


Ответы (2)


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

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

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

person Vatine    schedule 02.09.2015
comment
Спасибо! Что, если я все еще ожидаю сообщения B при обработке C и D? Я повторяю обработчик B в цикле2? Это очень многословно. - person NeoWang; 02.09.2015

Ты получил это.

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

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

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

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

person Pascal    schedule 02.09.2015