In what order does an Erlang process consume messages?
Are messages processed in a first-come-first-serve开发者_JAVA百科 basis or are they sorted by timestamp or something like that?
Order of messages is preserved between a process and another one. Reading from the FAQ:
10.9 Is the order of message reception guaranteed?
Yes, but only within one process.
If there is a live process and you send it message A and then message B, it's guaranteed that if message B arrived, message A arrived before it.
On the other hand, imagine processes P, Q and R. P sends message A to Q, and then message B to R. There is no guarantee that A arrives before B. (Distributed Erlang would have a pretty tough time if this was required!)
@knutin is right regarding how you can consume messages within a process. As an addition, note that you might use two subsequent receive statements to ensure that a certain message is consumed after another one:
receive
first ->
do_first()
end,
receive
second ->
do_second()
end
The receive statement is blocking. This will ensure that you never do_second()
before you do_first()
. The difference from @knutin's second solution is that, in that case, if something not important arrives just before an important one, you queue the important bit.
The mailbox is always kept in the order the messages arrived.
However, the order the messages are consumed is determined by your code.
If you have a plain process with a generic receive
clause that receives anything, the order you get messages are the same as the order they arrived in.
loop() ->
receive
Any ->
do_something(Any),
loop()
end.
However, if you have a selective receive
with match clauses, it will search the mailbox for messages of this specific type and consume the first matching message, effectively skipping non-matching messages. In the following example, if there are messages tagged as important in the queue, they will be processed before any other message. Note: Matching like this will search all messages in the queue, which is a problem for many messages. There has been some developments in this area, but I'm not up to speed.
loop() ->
receive
{important, Stuff} ->
do_something_important(Stuff),
loop();
Any ->
do_something(Any)
loop()
end.
to further define the answer, I would like to point the fact that, as stated above, messages that don't pattern match are skipped, but in reality they are simply put aside and then reintroduced in order (so first that any other message arrived after the not matching messages) for next receive pattern matching.
This problem really shows its worst when you have, for example, a gen_server behaviour module because in this case, having always the same pattern matching call scheme, messages not in scope are going to flood message queue unless you define a (ugly and error prone, IMHO) match-all pattern like:
receive
... -> ...;
... -> ...;
MatchAllPatterns -> ok.
end
精彩评论