views:

558

answers:

4

Hello,

Priority receive in Erlang can easily be implemented as follows:

prio() -> 
  receive 
    {priority, X} -> X 
  after 0 -> 
    receive 
      X -> X 
    end 
  end.

I am reading a paper called Priority Messaging made Easy in which they describe the following problem:

The main problem with the [code] example [above], is that we do not take into consideration that when evaluation is resumed from the inner blocking receive we may have more than one message in the mailbox. In a worst case scenario, all but the first, of potentially a huge number, of elements could be priority messages. In this scenario we would actually have accomplished the very opposite of what we intended to do.

I don't completely get this.

Question (1): I assume that the inner blocking receive will be 'called' (i.e. resumed) as soon as one message has arrived in the message queue, no? Is it realistic to assume that in the short time it takes to resume from the inner blocking receive, there would already be a whole bunch of messages waiting in the queue?

Question (2): Also, the worst case is described as a queue with one normal message an a lot of priority messages. Since all the receive clauses are first checked against the first message in the queue, and then against the second message in the queue, ...(source: this book, page 69-70) shouldn't this be: a lot of normal messages with at the end of the queue a priority message?

+3  A: 

Erlang being a radically concurrent language, there's no reason you couldn't have been sent several messages at the exact same time. Making assumptions along the lines of "Oh, this is fast -- it's so unlikely other threads would do something that conflicts in that little time" is essentially the same thing as closing your eyes and saying "There's no such thing as race conditions, there's no such thing as race conditions..."

Chuck
Don't forget clicking your Ruby slippers.
Charlie Martin
+1  A: 

On (1): Whether this assumption can be made depends on details of your situation. For example, all other processes may have been waiting for something to happen before sending you their messages.

On (2): In fact, it seems to me that the worst case would be no priority messages, as the mailbox would have to be traversed every time: "Has a priority message come in yet?"

Alexey Romanov
A: 

According to the erlang reference manual receive traverses the mailbox in time order. and blocks till a message matches the one of the clauses.

Given that it sounds like the inner recieve is going to block till it recieves a matching message. Because of this you might actually stack up priority messages while waiting for non-priority messages which is the opposite of what you want.

Too ways out of this predicament are throwing a new after clause on the inner receive. Or always match in the inner recieve.

Although looking at their function the inner clause should always match but I'm guessing this is what they were talking about.

Jeremy Wall
A: 

The statement you highlight is simply saying that if you are in the blocking inner receive block you could process a low priority message before a high priority message (because you are matching everything) which is not necessarily the intent.

It's a bit of an edge case - I've found that being efficient at processing the messages when you want some type of filtering is important. In other cases I've also monitored the process queue depth and altered my strategy accordingly. As an example of the latter a simple logging gen_server type process (which used cast to send the log message) could get rather backed up as writing the log messages to disk can be a lot slower than pushing the messages to the process. If the queue depth got too large I would discard the informational/spam type messages that I would normally log and only process (write to disk) the critical ones.

Alan Moore