send(self(), :first)
send(self(), {:greeting, "hi"})
send(self(), :last)
Processes communicate only by sending messages.
send/2 drops a message in the target's mailbox and
returns immediately; it never blocks and never fails,
even if the target is dead.
send(self(), :first)
send(self(), {:greeting, "hi"})
send(self(), :last)
receive takes the first message matching any
clause. Messages from one sender arrive in the order
they were sent.
receive do
msg -> IO.inspect(msg, label: "got")
end
got: :first
Selective receive: a clause can skip ahead to a message that matches, leaving earlier ones in the mailbox for later.
receive do
:last -> IO.puts("picked :last first")
end
receive do
{:greeting, text} -> IO.puts("then the greeting: #{text}")
end
picked :last first
then the greeting: hi
after sets a timeout in milliseconds. Without it,
receive waits forever.
receive do
:never_sent -> :ok
after
50 -> IO.puts("nothing arrived within 50 ms")
end
nothing arrived within 50 ms
after 0 checks the mailbox without waiting. A
common idiom to drain all pending messages.
for i <- 1..3, do: send(self(), {:job, i})
drain = fn drain, acc ->
receive do
{:job, i} -> drain.(drain, [i | acc])
after
0 -> Enum.reverse(acc)
end
end
IO.inspect(drain.(drain, []), label: "drained")
drained: [1, 2, 3]
Request/reply: include your own pid so the other process knows where to answer, and a unique ref so you can match this reply and not a stale one.
server =
spawn(fn ->
receive do
{:double, n, from, ref} -> send(from, {ref, n * 2})
end
end)
ref = make_ref()
send(server, {:double, 21, self(), ref})
receive do
{^ref, result} -> IO.inspect(result, label: "reply")
after
1_000 -> IO.puts("timed out")
end
reply: 42
Sending to a dead process is silently ignored.
send(server, :anyone_there?)
IO.puts("send to a dead pid returned without error")
send to a dead pid returned without error
Pitfall: a
receivethat never matches some message leaves it in the mailbox forever. Every laterreceiverescans it, so the process gets slower and leaks memory. Long-running loops need a catch-all clause (log and drop), which is exactly what GenServer'shandle_info/2gives you.
Pitfall: don't forget the
^in{^ref, ...}. Without the pin,refis rebound and the clause matches any two-element tuple, including replies meant for someone else.