gen_server:selective_receive/1

Ulf Wiger <>
Tue Jan 28 14:25:57 CET 2003


On Tue, 28 Jan 2003, Per Bergqvist wrote:

>Except that the tag is changed from '$gen_cast' to 'cast'
>etc. isn't this equivalent to a receive ... after 0 ?
>
>/Per

OK, to follow up on the idea a step further, below's an
implementation that actually works.

The following code was written to test the new
implementation (in a gen_server callback):

handle_call(start_test, From, State) ->
    timer:sleep(3000),
    Reply = timer:tc(
	      gen_server,fold_messages,
	      [
	       fun({cast, _} = Msg, Acc) ->
		       {true, [Msg|Acc]};
		  (Msg, Acc) ->
		       false
	       end, []]),
    {reply, Reply, State}.


Basically gen_server:fold_messages(Fun, Acc), where
Fun(Msg, Acc) should return {true, Acc1} or false (in the
former case, the message is consumed, in the latter, not),
had the following performance on my machine:

# msgs in the queue	exec. time (us)
10			6.5
100			300
1,000			3,000
10,000			40,000

The cost is, I think, reasonable. Still, after having gotten
some sleep, I've decided that it doesn't solve the problem.
It just reduces it (possibly creating other problems in the
process.) The real problem is one of serialization, and
cannot be addressed this way. I withdraw my suggestion. Bad
idea.

/Uffe


fold_messages(Fun, Acc) ->
    {_, Messages} = process_info(self(), messages),
    Parent = get_parent(),
    fold(Messages, Fun, Acc, Parent).

fold([{'$gen_call',From,Request} = X|Rest], Fun, Acc, Parent) ->
    fold_one({call,From,Request}, X, Fun, Acc, Rest, Parent);
fold([{'$gen_cast',Msg} = X|Rest], Fun, Acc, Parent) ->
    fold_one({cast, Msg}, X, Fun, Acc, Rest, Parent);
fold([{'EXIT',Pid,Why} = X|Rest], Fun, Acc, Parent) when Pid /= Parent ->
    fold_one(X, X, Fun, Acc, Rest, Parent);
fold([Msg|Rest], Fun, Acc, Parent) when size(Msg) == 6,
					element(1,Msg) == system ->
    %% ignore
    fold(Rest, Fun, Acc, Parent);
fold([Msg|Rest], Fun, Acc, Parent) ->
    fold_one({info, Msg}, Msg, Fun, Acc, Rest, Parent);
fold([], _, Acc, _) ->
    Acc.


fold_one(Msg, X, Fun, Acc, Rest, Parent) ->
    NewAcc = case Fun(Msg, Acc) of
		 {true, Acc1} ->
		     %% consume the message
		     receive X -> X end,
		     Acc1;
		 false ->
		     Acc
	     end,
    fold(Rest, Fun, NewAcc, Parent).


-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Strategic Product & System Management
 / / /     Ericsson Telecom AB, ATM Multiservice Networks




More information about the erlang-questions mailing list