Concurrency Patterns

Production pools: poolboy, worker_pool, pooler.

26.1 Synchronous call (RPC over messages)

call(Server, Request) ->
    Ref = monitor(process, Server),
    Server ! {call, {self(), Ref}, Request},
    receive
        {Ref, Reply} -> demonitor(Ref, [flush]), Reply;
        {'DOWN', Ref, process, _, Reason} -> error({server_down, Reason})
    after 5000 ->
        demonitor(Ref, [flush]), error(timeout)
    end.

26.2 Parallel map

pmap(F, List) ->
    Parent = self(),
    Refs = [begin
                Ref = make_ref(),
                spawn_link(fun() -> Parent ! {Ref, F(X)} end),
                Ref
            end || X <- List],
    [receive {Ref, Result} -> Result end || Ref <- Refs].

26.3 Worker pool

Production pools: poolboy, worker_pool, pooler.

start_pool(N, F) -> [spawn_link(fun() -> worker(F) end) || _ <- lists:seq(1, N)].
worker(F) ->
    receive
        {job, From, Arg} -> From ! {result, F(Arg)}, worker(F);
        stop -> ok
    end.

26.4 Publish/subscribe

Use pg (process groups) or a registry process; pg:join/2, pg:get_members/1, broadcast with a list comprehension.

26.5 Timeouts & periodic tasks

loop(State) ->
    receive
        tick -> erlang:send_after(1000, self(), tick), loop(do_work(State))
    end.

26.6 Back-pressure

Unbounded mailboxes are the #1 cause of BEAM memory blowups. Use synchronous calls, credit-based flow control, or bounded queues; monitor message_queue_len.

26.7 Priority messages (OTP 28+)

A receiver can create a priority alias (alias([priority])); messages sent with erlang:send(Alias, Msg, [priority]) jump ahead of ordinary messages.