Erlang
for Concurrent Programming
and a new state are given in the return value. The process’s “eternally looping function” is implemented in the
library. This allows for simple unit testing of the callback
functions.
Large Erlang applications make heavy use of behaviours—direct use of the raw message-sending or receiving expressions is
uncommon. In the Ericsson AXD301
telecom switch—the largest known
Erlang project, with more than a million
lines of code—nearly all the application
code uses standard behaviours, a majority of which are the server behaviour. 4
Erlang’s OTP standard library provides three main behaviours:
Generic server (gen_server). The
generic server is the most common
behaviour. It abstracts the standard
request-response message pattern used
in client-server or remote procedure
call protocols in distributed computing.
It provides sophisticated functionality
beyond our simple server module:
• Responses can be delayed by the server
or delegated to another process.
• Calls have optional timeouts.
• The client monitors the server so that
it receives immediate notification of a
server failure instead of waiting for a
timeout.
Generic finite state machine
(gen_fsm). Many concurrent algorithms are specified in terms of a finite
state machine model. The OTP library
provides a convenient behaviour for
this pattern. The message protocol that
it obeys provides for clients to signal
events to the state machine, possibly
waiting for a synchronous reply. The
application-specific callbacks handle
these events, receiving the current state and passing a
new state as a return value.
Generic event handler (gen_event). An event manager
is a process that receives events as incoming messages,
then dispatches those events to an arbitrary number of
event handlers, each of which has its own module of
callback functions and its own private state. Handlers can
be dynamically added, changed, and deleted. Event handlers run application code for events, frequently selecting
a subset to take action upon and ignoring the rest. This
behaviour naturally models logging, monitoring, and
“pubsub” systems. The OTP library provides off-the-shelf
A
Make a set of server calls in parallel and return a
% list of their corresponding results.
Calls is a list of {Server, Params} tuples.
multicall1(Calls) ->
Ids = [send_call(Call) || Call <- Calls],
collect_replies(Ids).
4
Send a server call request message.
send_call({Server, Params}) ->
Id = make_ref(),
Server {call, {self(), Id}, Params},
Id.
Collect all replies in order.
collect_replies(Ids) ->
[receive {Id, Result} -> Result end || Id <- Ids].
B
multicall2(Calls) ->
Parent = self(),
Pids = [worker(Parent, Call) || Call <- Calls],
wait_all(Pids).
worker(Parent, {Server, Params}) ->
spawn(fun() -> create a worker process
Result = server:call(Server, Params),
Parent {self(), Result}
end).
wait_all(Pids) ->