gen_erver parallel call (was Re: spawn without linking?)

Sean Hinde sean.hinde@REDACTED
Fri Apr 23 13:03:45 CEST 2004


On 22 Apr 2004, at 23:32, Sean Hinde wrote:

>
> On 21 Apr 2004, at 04:20, Shawn Pearce wrote:
>
>> Actually, it is that hard to do...  the OTP behaviors offer lots
>> of well tested/debugging implementations which handle the border
>> cases extremely well.  Which a naive quick implementation using
>> just the basic spawn_link/* and trap_exit won't get quite right on
>> the first few tries.
>>
>> OTP rocks for that reason alone... but yea, gen_server isn't the
>> most "Erlang" way to write a server, but its the Erlang/OTP way.
>
> How about this which I had fun writing today. It is almost Erlangish, 
> and it is something like OTP, and it is exactly Joe's selective 
> receive example. I can't decide whether it is ugly or profoundly 
> beautiful.
>

I've made the intent clearer I think in this version. This is going to 
be so useful for us that I'm sure it must be of some use for someone 
else:


%% @doc Call one or more gen_servers multiple times with different
%% queries concurrently. This is equivalent to calling
%% gen_server:call(Name, Request, Timeout) multiple times except that
%% they are handled in parallel.
%%
%% @spec multi_call(Requests, Timeout::integer()) ->
%%          {[{Name, Result}], [Failure]}
%% Requests = [{Name, Request}]
%% Name = pid() | atom()
%% Request = term()
%% Result = term()
%% Failure = pid() | atom()
multi_call(Requests, Timeout) when is_list(Requests), 
is_integer(Timeout) ->
     Mrefs = lists:map(fun({Name, Req}) ->
                               Mref = erlang:monitor(process, Name),
                               Name ! {'$gen_call', {self(), Mref}, Req},
                               {Name, Mref}
                       end, Requests),
     Start = now(),
     lists:foldl(
       fun({Name, Mref}, {Succ, Fail}) ->
               Time_since_start = timer:now_diff(now(), Start) div 1000,
               Timeout_val = max(Timeout - Time_since_start, 0),
               receive
                   {Mref, Reply} ->
                       erlang:demonitor(Mref),
                       receive
                           {'DOWN', Mref, _, _, _} ->
                               {[{Name, Reply}|Succ], Fail}
                       after 0 ->
                               {[{Name, Reply}|Succ], Fail}
                       end;
                   {'DOWN', Mref, _, _, _} ->
                       {Succ, [Name|Fail]}
               after Timeout_val ->
                       erlang:demonitor(Mref),
                       {Succ, [Name|Fail]}
               end
       end, {[],[]}, Mrefs).

max(A, B) when A >= B -> A;
max(A, B)             -> B.




More information about the erlang-questions mailing list