Skip to content
Processes and Message Passing
step 1/5

Reading — step 1 of 5

Learn

~1 min readStructs and Processes

Elixir's killer feature: lightweight processes (running on the BEAM VM). Millions can coexist; they share nothing; they communicate via messages.

pid = spawn(fn ->
    receive do
        {:hello, name} -> IO.puts("Hello, #{name}")
        :stop -> IO.puts("goodbye")
    end
end)

send(pid, {:hello, "Ada"})       # the spawned process prints "Hello, Ada" and dies
  • spawn/1 starts a new process running the given function. Returns its PID.
  • send(pid, message) queues a message to that process.
  • receive do ... end blocks until a matching message arrives.
  • Each process has a mailbox — messages queue up FIFO.

Long-lived processes loop:

defmodule Counter do
    def start, do: spawn(fn -> loop(0) end)

    def loop(count) do
        receive do
            :inc -> loop(count + 1)
            {:get, from} ->
                send(from, count)
                loop(count)
            :stop -> :ok
        end
    end
end

pid = Counter.start()
send(pid, :inc)
send(pid, :inc)
send(pid, {:get, self()})
receive do n -> IO.puts(n) end    # 2

self() returns the current process's PID.

Key properties:

  • Processes share NO memory. Messages are copied.
  • A crash in one process doesn't take down others.
  • Processes are isolated → fault tolerance is built in.

Real production code uses GenServer — a higher-level abstraction over receive loops with helpers for sync calls (call), async messages (cast), and supervision. Worth learning after this foundation.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…