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.