[erlang-questions] Message Receive Semantics (was eep:MultiplePatterns)

Jay Nelson <>
Sun Jun 8 23:54:12 CEST 2008


David Mercer posted a submission that performed as the
requirements stated. In between my post and David's, Valentin
pointed out that requirements documents may not be my calling.

The solution David posted is a cleanly written separation of the
various priorities, and it avoids polling by quitting after the message
queue is cleared.  Of course, he perfectly satisfied my requirements
as restated from Valentin's original.

In a real operational situation a few things would be different:

1) New messages can arrive at any time
2) Newly arriving higher priority messages should interrupt a
      lesser priority loop
3) The 5:3:1 is an artificial substitute for true process priorities


To allow new messages, I believe your clean separation has to
be violated. This typically occurs by nesting receives as Valentin
did (the after clause of high priority contains a receive that includes
both high and normal).

The 5:3:1 is  just a way to say that given a single message queue
and a single process, allow some of each message type to get
processed to avoid constant priority pre-emption without exhibiting
priority inversion (too many low messages when there are higher
priority messages).

To leverage erlang strengths, use a router on your single queue
and a separate process for each of the priorities.  This accomplishes
the following:

1) One scan of the message queue is possible (although
      selective receive may still be useful depending on the
      application).

   * [Using your approach, there will be one scan per priority level --
       suppose we have 8 priorities and the queue has 1000 low priority
       messages.  There will be 7 scans of all the messages to do
       nothing followed by a scan that processes them all, unless we
       have to check for a newly arriving higher priority message in
       which case there will be 999 more unsuccessful scans (x 7
       higher priorities) of a queue that decreases in length by
       1 each time.]

2) You now have uniform priority queues per process.  You can
      process in order, or use selective receive to thread a single
      conversation, but you don't have to worry about priority issues.

3) You now have separate processes which can be bumped or
      reduced in priority, or fed messages quickly or slowly as the
      router wishes to balance the relative amount of processing.

4) Adding a few new priority levels doesn't ripple through receive
      statements, nor does it multiply the number of message scans.
      The new priorities require a few new spawns and pattern to
      route messages.

The real message is: be careful if you find yourself wishing for
priority message handling.  Look for alternative ways to route
messages to accomplish the intended effect.  Priority is a hack
for single channels to work as if they had more smarts, more
horsepower and to simulate multiple channel communications.

In a threaded world, I constantly come across architectures
with callbacks on events.  Eventually, the implementer wants
priority because the message queues are too long and they
can't get to the messages that need handling immediately.
It is a symptom of an architectural issue, and a patch to make
it work, rather than reconsidering the whole communications
structure.

With erlang, it is easy to reorganize the architecture or
communications structure without impacting the application
logic.  It is much harder in other languages, so the lazy way
is a quick patch rather than an architectural refactoring.


There is a completely separate discussion about how to
recognize priority properly (we had this a few months back).
In our examples here, the message was magically marked
with the correct priority.  To do that requires all senders to
have global knowledge and logic to set the proper level.
A better approach is to mark the messages with the data
needed to make a decision, but allow the router process
to use its own logic to determine the priorities based on
the content provided to it.  It enables a simple logic change
in the router to affect the throughput of the entire system.
If the logic is spread throughout the system, or is globally
determined, the impact of priority change is large.

jay




More information about the erlang-questions mailing list