Elixir进程基础 #

一、进程概念 #

1.1 什么是进程 #

Elixir进程是轻量级的并发单元,不是操作系统进程。它们:

  • 非常轻量(约2KB初始内存)
  • 创建和销毁成本低
  • 可以同时运行数百万个
  • 通过消息传递通信

1.2 进程与操作系统进程 #

特性 Elixir进程 OS进程
内存 ~2KB ~MB
创建成本 极低
数量 百万级 数百
通信 消息传递 IPC

二、创建进程 #

2.1 spawn #

elixir
iex(1)> pid = spawn(fn -> IO.puts("Hello from process!") end)
Hello from process!
#PID<0.123.0>

创建并链接进程(一个崩溃会影响另一个):

elixir
iex(1)> spawn_link(fn -> raise "Error!" end)
** (RuntimeError) Error!

2.3 spawn_monitor #

创建并监控进程:

elixir
iex(1)> {pid, ref} = spawn_monitor(fn -> raise "Error!" end)
{#PID<0.123.0>, #Reference<0.1234567890.1234567890.123456>}

iex(2)> flush()
{:DOWN, #Reference<0.1234567890.1234567890.123456>, :process, #PID<0.123.0>,
 %RuntimeError{message: "Error!"}}
:ok

2.4 self #

获取当前进程PID:

elixir
iex(1)> self()
#PID<0.1.0>

三、消息传递 #

3.1 发送消息 #

elixir
iex(1)> pid = spawn(fn ->
...>   receive do
...>     msg -> IO.puts("Received: #{inspect(msg)}")
...>   end
...> end)
#PID<0.123.0>

iex(2)> send(pid, :hello)
Received: :hello
:hello

3.2 接收消息 #

elixir
iex(1)> receive do
...>   {:ok, data} -> "Success: #{data}"
...>   {:error, reason} -> "Error: #{reason}"
...> after
...>   1000 -> "Timeout"
...> end

3.3 消息队列 #

每个进程都有消息队列:

elixir
iex(1)> self() |> Process.info(:messages)
{:messages, []}

iex(2)> send(self(), :hello)
:hello

iex(3)> self() |> Process.info(:messages)
{:messages, [:hello]}

四、进程通信模式 #

4.1 请求-响应 #

elixir
defmodule Echo do
  def start do
    spawn(fn -> loop() end)
  end

  defp loop do
    receive do
      {from, msg} ->
        send(from, {:echo, msg})
        loop()
    end
  end

  def echo(pid, msg) do
    send(pid, {self(), msg})

    receive do
      {:echo, response} -> response
    after
      1000 -> {:error, :timeout}
    end
  end
end

pid = Echo.start()
Echo.echo(pid, "Hello")

4.2 状态保持进程 #

elixir
defmodule Counter do
  def start(initial \\ 0) do
    spawn(fn -> loop(initial) end)
  end

  defp loop(count) do
    receive do
      {:increment, from} ->
        new_count = count + 1
        send(from, {:ok, new_count})
        loop(new_count)

      {:decrement, from} ->
        new_count = count - 1
        send(from, {:ok, new_count})
        loop(new_count)

      {:get, from} ->
        send(from, {:ok, count})
        loop(count)
    end
  end

  def increment(pid) do
    send(pid, {:increment, self()})
    receive do
      {:ok, count} -> count
    end
  end

  def decrement(pid) do
    send(pid, {:decrement, self()})
    receive do
      {:ok, count} -> count
    end
  end

  def get(pid) do
    send(pid, {:get, self()})
    receive do
      {:ok, count} -> count
    end
  end
end

4.3 广播 #

elixir
defmodule Broadcaster do
  def broadcast(pids, msg) do
    Enum.each(pids, fn pid -> send(pid, msg) end)
  end
end

五、进程链接 #

elixir
iex(1)> pid = spawn(fn ->
...>   receive do
...>     _ -> raise "Error!"
...>   end
...> end)
#PID<0.123.0>

iex(2)> Process.link(pid)
true

iex(3)> send(pid, :trigger)
** (RuntimeError) Error!
elixir
iex(1)> Process.unlink(pid)
true

5.3 进程标志 #

elixir
iex(1)> Process.flag(:trap_exit, true)
false

iex(2)> spawn_link(fn -> raise "Error!" end)
#PID<0.123.0>

iex(3)> flush()
{:EXIT, #PID<0.123.0>, %RuntimeError{message: "Error!"}}
:ok

六、进程监控 #

6.1 monitor #

elixir
iex(1)> pid = spawn(fn ->
...>   receive do
...>     _ -> :ok
...>   end
...> end)
#PID<0.123.0>

iex(2)> ref = Process.monitor(pid)
#Reference<0.1234567890.1234567890.123456>

iex(3)> send(pid, :stop)
:stop

iex(4)> flush()
{:DOWN, #Reference<0.1234567890.1234567890.123456>, :process, #PID<0.123.0>, :normal}
:ok

6.2 demonitor #

elixir
iex(1)> Process.demonitor(ref)
true

6.3 链接与监控的区别 #

特性 link monitor
方向 双向 单向
崩溃传播
多次监控
用途 监督树 监控

七、进程信息 #

7.1 Process.info #

elixir
iex(1)> pid = self()
#PID<0.1.0>

iex(2)> Process.info(pid, :status)
{:status, :running}

iex(3)> Process.info(pid, :message_queue_len)
{:message_queue_len, 0}

iex(4)> Process.info(pid, [:status, :message_queue_len])
[status: :running, message_queue_len: 0]

7.2 进程状态 #

  • :running - 正在运行
  • :waiting - 等待消息
  • :runnable - 可运行
  • :suspended - 挂起

7.3 进程列表 #

elixir
iex(1)> Process.list()
[#PID<0.1.0>, #PID<0.2.0>, ...]

八、进程注册 #

8.1 注册名称 #

elixir
iex(1)> pid = spawn(fn -> loop() end)
#PID<0.123.0>

iex(2)> Process.register(pid, :my_process)
true

iex(3)> send(:my_process, :hello)
:hello

8.2 查找注册进程 #

elixir
iex(1)> Process.whereis(:my_process)
#PID<0.123.0>

iex(2)> Process.registered()
[:my_process, :kernel, ...]

8.3 取消注册 #

elixir
iex(1)> Process.unregister(:my_process)
true

九、进程优先级 #

elixir
iex(1)> Process.flag(:priority, :high)
:normal

优先级:

  • :low
  • :normal
  • :high
  • :max

十、总结 #

本章学习了:

函数 用途
spawn/1 创建进程
spawn_link/1 创建并链接进程
spawn_monitor/1 创建并监控进程
send/2 发送消息
receive/1 接收消息
self/0 获取当前PID
Process.link/1 链接进程
Process.monitor/1 监控进程
Process.register/2 注册进程名

准备好学习进程通信了吗?让我们进入下一章。

最后更新:2026-03-27