[erlang-questions] Calling multiple processes simultaneously

Geoff Cant <>
Mon May 23 22:20:23 CEST 2011


gen_server:call boils down to

call(Server, Msg, Timeout) ->
   Ref = monitor(Server), % or make_ref()
   Server ! {'$gen_call$', {self(), Ref}, Msg},
   receive
       {Ref, Reply} -> Reply
       {'DOWN', Ref, _, _, Reason} -> exit(Reason)
   after Timeout ->
       exit(timeout)
   end.

If you do:
barrier(Servers, Msg) -> [ gen_server:call(S, Msg) || S <- Servers ],
ok.

Then you'll wait at least Servers*2 message delays, and at worst Servers
* the gen_server call default timeout (5s).

You could do all the calls concurrently with something like:

call(Servers, Msg, Timeout) ->
    Refs = [{S, monitor(S)}|| S <- Servers],
    [S ! {'$gen_call$', {self(), Ref}, Msg}
     || {S, Ref} <- Refs ],
    collect_replies(Refs, Timeout).

collect_replies([], _) -> [];
collect_replies([{S, Ref} | Rest], Timeout) ->
    receive
        {Ref, Reply} -> [{S, Reply} | collect_replies(Rest, Timeout)];
        {'DOWN', Ref, _, _, Reason} -> [{S, {error, Reason}} |
            collect_replies(Rest, Timeout)]
    after Timeout ->
        %% Timeout is now expired for all servers.
        [{S, {error, timeout}} | collect_replies(Rest, 0)]
    end.

This contains a basic attempt to not wait N*Timeout at worst, but could
be made closer to 1 timeout max by measuring the time from entering
collect_replies to receiving a Ref message and subtracting that from
Timeout before recurring.

This code doesn't handle all the special cases that gen:call does (
https://github.com/erlang/otp/blob/master/lib/stdlib/src/gen.erl#L191 ),
but should illustrate the idea.

--
Geoff Cant

Martin Dimitrov <> writes:

> Hi, please, advise on this one,
>
> We have several hundred processes (gen_servers) . At one point the
> program has to send them a message that needs to be handled before the
> calling process can continue executing. This naturally led us to use
> gen_server:call in loop over the processes.
>
> I started to wonder if there is a more efficient way of doing it since
> the calling process doesn’t care about the return value – just needs to
> be sure that all processes had handled the message. Can we somehow call
> the processes simultaneously? Something similar to gen_server:multi_call
> but for one node with different processes?
>
> Regards,
>
> Martin
>
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions



More information about the erlang-questions mailing list