sign in
Home | Updates | Pages | Users | Admin | Help

erlangbasics

Erlang Basics

Erlang Mantra

Origin (PDF): Making Reliable Distributed Systems in the Presence of Software Errors

  • Everything is a process.
  • Processes are strongly isolated.
  • Process creation and destruction is a lightweight operation.
  • Message passing is the only way for processes to interact.
  • Processes have unique names.
  • If you know the name of a process you can send it a message.
  • Processes share no resources.
  • Error handling is non-local.
  • Processes do what they are supposed to do or fail.

...The statement about error handling is perhaps less obvious. When we make a fault-tolerant system we need at least two physically separated computers. Using a single computer will not work, if it crashes, all is lost. The simplest fault-tolerant system we can imagine has exactly two computers, if one computer crashes, then the other computer should take over what the first computer was doing. In this simple situation even the software for fault-recovery must be non-local; the error occurs on the first machine, but is corrected by software running on the second machine.

Common Concurrency Patterns

Cast (send msg)

A ! B

Event (get msg)

receive A -> A end

Call (RPC)

A ! {self(), B},
receive 
  {A, Reply} -> 
    Reply
  end

Callback

receive
  {From, A} ->
    From ! F(A)
  end

Some trickery follows ;).

Here something cool – Parallel RPC:

%% Usage: par_rpc([A, B, C], M)

par_rpc(Ps, M) ->
  Self = self(),
  Tags = map(fun(I) ->
               Tag = make_ref(),
               spawn(fun() ->
                       Val = rpc(I, M),
                       Self ! {Tag, Val}
                     end),
               Tag
               end, Ps),
   yield(Tags).

yield([]) -> [];
yield([H|T]) ->
  Val1 = receive {H, Val} -> Val end,
  [Val1|yield(T)].
Parallel map implementation in Erlang:
%% Map function F over list L in parallel.
par_map(F, L) ->
  Parent = self(),
  [ receive 
      {Pid, Result} -> Result  end  || 
          Pid <- [ spawn( fun() -> Parent ! {self(), F(X)}  end) || X <- L ]
  ].

Behaviours

based on Joe Armstrong post to the ML

gen_server

Here is a mini gen_server:
rpc(Pid, Q) ->
  Pid ! {self(), Q},
  receive
    {Pid, Reply} -> Reply
  end.

loop(State, Fun) ->
  receive
    {swapCode, Fun1} ->
       loop(State, Fun1);
    {From, Q} ->
       {Reply, State1} = Fun(Q, State),
       From ! {self(), Reply},
       loop(State1, Fun)
  end.
Here’s one that crashes the client if the query in the server results in a crash:
rpc(Pid, Q) ->
  Pid ! {self(), Q},
  receive
    {ok, Pid, Reply} -> Reply;
    {oops, Pid, Why} -> exit(Why)
  end.

loop(State, Fun) ->
  receive
    {swapCode, Fun1} ->
       loop(State, Fun1);
    {From, Q} ->
       case (catch Fun(Q, State)) of
         {'EXIT', Why} ->
            From ! {oops, self(), Why},
            loop(State, Fun);
         {Reply, State1} ->
            From ! {ok, self(), Reply},
            loop(State1, Fun)    
       end
  end.

gen_event

send_event(Pid, Event) ->
   Pid ! {event, Event}.

register(Pid, F) ->
   Pid ! {register, F}.

loop(Funs) ->
   receive
      {register, Fun} ->
         loop([Fun | Funs]);
      {event, Event} ->
         lists:foreach(fun(F) -> F(Event) end, Funs),
         loop(Funs)
   end.

See also


Powered by JunebugWiki v0.0.31 Page last edited by stoyan on May 30, 2007 04:15 PM (diff)
[readonly] Version 5 (current) «olderversions