模块 01查看课程目录
00起跑线:两门语言,一台机器01先建立 BEAM 心智模型02Elixir 基础:让数据流过函数03Erlang 基础:读懂 BEAM 的母语04两种语法,一套语义05从裸进程理解并发06从手写循环推导 OTP07监督树与应用08状态、吞吐与背压09分布式与可运维性10Erlang ↔ Elixir 互操作11综合项目:可靠任务调度器
01
地基零基础BEAMOTP

先建立 BEAM 心智模型

不可变数据、轻量进程与故障隔离,是后续所有章节的坐标系。

3检查点
3 小时预计完成
为什么先学这个

先修正心智模型,再增加 API

如果把 BEAM 进程等同于操作系统进程,就会高估创建成本;如果把它等同于共享内存线程,又会错误地寻找锁。BEAM 的选择是:大量隔离的小进程,以消息通信,让局部失败可以被观察、重启和限制。

学完你能做到

可验证的学习目标

  • 能区分 BEAM 进程、OS 进程和线程
  • 能解释 mailbox、独立堆和抢占式调度之间的关系
  • 能预测不可变更新和模式匹配的结果
前置知识
  • 完成起跑线
  • 见过 tuple、list、map
最小心智模型

先抓住三个词

01

轻量进程

由 BEAM 调度的隔离执行单元。它不是 OS 进程,创建和切换成本都更低。

02

mailbox

每个进程自己的消息队列。发送是异步的,接收方通过模式选择下一条可处理消息。

03

reduction

BEAM 衡量进程工作量的近似单位。调度器用它避免单个进程长期霸占执行权。

双语代码桥

先对齐协议,再看标点

状态不是被原地修改;每次收到消息,进程都以一个新参数进入下一轮递归。

Elixir
counter = fn loop, total ->
  receive do
    {:add, n} -> loop.(loop, total + n)
    {:read, caller} ->
      send(caller, {:total, total})
      loop.(loop, total)
  end
end

pid = spawn(fn -> counter.(counter, 0) end)
Erlang
Counter = fun Loop(Total) ->
  receive
    {add, N} -> Loop(Total + N);
    {read, Caller} ->
      Caller ! {total, Total},
      Loop(Total)
  end
end,

Pid = spawn(fun() -> Counter(0) end).
LAB
可运行实验

看见 mailbox,而不是想象共享变量

约 15–25 分钟

启动计数器,连续发送三条消息,再询问状态。重点不是答案 6,而是状态如何只存在于那个进程的下一次递归参数里。

  1. 01

    向进程连续发送 `{:add, 1}`、`{:add, 2}`、`{:add, 3}`

  2. 02

    发送带自己 PID 的 `{:read, self()}`

  3. 03

    用 `Process.info(pid, :message_queue_len)` 观察队列长度

在终端 / shell 中运行
send(pid, {:add, 1}); send(pid, {:add, 2}); send(pid, {:add, 3})
预期观察
  • 最终回复为 `{:total, 6}`
  • 计数器没有暴露可被其他进程直接修改的内存地址
故意弄坏

删除 `{:read, caller}` 分支,再发送读取消息。进程不会自动报错;消息会留在 mailbox 中。

这个实验能证明

这个递归循环可以通过消息串行化自己的状态更新。

这个实验不能证明

它不能证明系统没有竞态,也不能证明任意 mailbox 都不会无限增长。

快速自测

一个进程收到无法匹配当前 receive 子句的消息时,通常会怎样?

本章挑战

画出三进程天气站

只用纸或文本画出 collector、sensor、dashboard 三个进程和它们的消息协议,并标明每条消息由谁创建、谁消费。

提示 1轻推一下

消息名称应表达业务含义,不要只写 `data`。

提示 2缩小问题

查询类消息需要返回地址或引用。

提示 3接近实现

考虑 dashboard 暂时离线时,collector 的 mailbox 会发生什么。

提示 4用验收标准反推

从下面每一条验收标准倒推一个最小测试。若某条无法写成测试,先把表述改成可观察结果。

完成标准
  • 每条消息都有明确发送者与接收者
  • 状态归属到具体进程
  • 至少指出一个队列可能增长的位置
带走这三句话

复习卡

  1. 1BEAM 进程通过隔离降低共享状态的复杂度,但不会自动消灭协议错误。
  2. 2递归参数是进程状态的一种常见表达。
  3. 3无法匹配的消息会留下来;mailbox 长度是重要运行指标。
继续核对

本章一手资料

Erlang ProcessesElixir Processes