[erlang-questions] [RFC] smarter receive

Roger Larsson <>
Fri Nov 10 00:06:33 CET 2006


Is it impossible to make the current receive smarter?

>From Concurrent Programming in ERLANG:

priority_receive() ->
	receive
		interrupt ->
			interrupt
		after 0 ->
			receive AnyMessage ->
				AnyMessage
			end
	end



Suppose the input queue has grown long.
The first receive above walks the queue and finds nothing.
Why not remember this position for next time?
Since the test is constant none of the already scanned messages will match 
next time either!

Simple rule: unless the match has changed it is possible to restart from the 
previous position. This holds even for AnyMessage since it matched the first
message it can continue from there the next time.

A more problematic example would be

receive_next(Pid) ->
	receive
		{Pid, Value} -> ...
	end.

But note that even in the last case a smart receive scanner could skip
all non tuples and all non two-tuples and never having to revisit them.
(It might be possible to be smarter than that - receive could keep the 
previously matched value  {<123.123.123>, _ })

Now lets try this on your example:

  loop(State) ->
       receive	%% *1
          {pause, _From} ->
		wait_for_resume(),
		loop(State)
	after 0 ->
		receive %% *2
 			{pause, _From} ->
				wait_for_resume(),
				loop(State)
			{DataMsg, From} ->
				NewState = send_response(From, DataMsg),
				loop(NewState)
		end
      end.

  wait_for_resume() ->
        receive %% *3
            {resume, _From} ->> ok
        end.

Receive *1 would skip all non two tuples with first tuple 'pause'.
Receive *3 would skip all non two tuples with first tuple 'resume'.
Receive *2 would skip all non two tuples.
AND since the process does no other receive (unless send_response does...)
any message skipped by all three will NEVER be received...

An improvement could be to add some syntaxtic sugar to avoid repeating the
prioritized part of the receive... Something like.

receive
	{prio1, Data} -> ...
	{prio2a, Data} after 0 -> ...
	{prio2b, Data} after 0 -> ...
	Anything after 1000 -> report_old(Anything)
	after 10000 -> timeout...
end.
In core Erlang this would be expanded to three receive statements. 

(It would be possible to cache one message_scan_location per
match - reusing it from any receive in that process!
Remaining to solve is where to start the scan - prio2a and prio2b could have
different message_scan_locations so begin with the oldest.. which one is
is oldest? And caches works well until you reach the magic limit where
things falls apart...)

Comments?

/RogerL




More information about the erlang-questions mailing list