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