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