第5章:Erlang的Actor模型(Actor Model)
一、导读
1.1 本章学习目标
第5章介绍 Actor 模型——Erlang 的并发基石。在 Actor 模型中,每个 Actor 是一个独立的计算单元,通过消息传递进行通信,不共享任何状态。
本章的核心学习目标包括:
- 理解 Actor 模型的核心概念
- 掌握消息传递的异步特性
- 理解监督树和容错机制
- 学会用 Actor 构建容错系统
1.2 为什么本章如此重要
Actor 模型被 Go、Elixir、Akka、Orleans 等众多框架采用。它的核心理念——"共享 nothing,通过消息通信"——是构建分布式系统的基础。Erlang 用 Actor 模型构建了电信级的99.999%可用性系统。
1.3 核心问题引导
Actor 模型和线程+锁模型有什么本质区别?
消息传递为什么比共享内存更安全?
监督树是如何实现容错的?
Actor 模型适合什么类型的应用?
二、核心概念详解
2.1 Actor 基础
erlang
%% 创建 Actor
-module(counter).
-export([start/0, loop/1]).
start() -> spawn(fun() -> loop(0) end).
loop(Count) ->
receive
{increment, From} ->
NewCount = Count + 1,
From ! {ok, NewCount},
loop(NewCount);
{get, From} ->
From ! {ok, Count},
loop(Count);
stop ->
ok
end.
%% 使用
Pid = counter:start(),
Pid ! {increment, self()},
receive {ok, Count} -> io:format("Count: ~p~n", [Count]) end.2.2 消息传递
erlang
%% 异步消息传递:发送后立即返回
Pid ! {message, data},
%% 同步等待回复
Rpc = fun(Pid, Msg) ->
Pid ! {self(), Msg},
receive
{Pid, Reply} -> Reply
after 5000 ->
{error, timeout}
end
end.2.3 监督树
erlang
-module(supervisor).
-behaviour(supervisor).
init(_) ->
{ok, {
{one_for_one, 5, 60},
[
{worker1, {worker, start_link, []},
permanent, 5000, worker, [worker]},
{worker2, {worker, start_link, []},
permanent, 5000, worker, [worker]}
]
}}.
%% 重启策略:
%% one_for_one: 只重启崩溃的进程
%% one_for_all: 所有进程都重启
%% rest_for_one: 崩溃进程及其后面的进程重启三、实战案例
3.1 案例一:简单的聊天室
erlang
-module(chat_room).
-export([start/0, join/2, send/2, leave/2]).
start() ->
register(chat_room, spawn(fun() -> loop([]) end)).
join(Room, Name) ->
Room ! {join, self(), Name},
ok.
send(Room, Message) ->
Room ! {send, self(), Message},
ok.
leave(Room, Name) ->
Room ! {leave, self(), Name},
ok.
loop(Members) ->
receive
{join, Pid, Name} ->
io:format("~s joined~n", [Name]),
loop([{Pid, Name} | Members]);
{send, From, Message} ->
FromName = proplists:get_value(From, Members),
lists:foreach(
fun({Pid, Name}) ->
case Pid =:= From of
true -> ok;
false -> Pid ! {message, FromName, Message}
end
end,
Members
),
loop(Members);
{leave, Pid, Name} ->
io:format("~s left~n", [Name]),
loop(proplists:delete(Pid, Members))
end.四、本章小结
Actor 模型:独立计算单元,通过消息传递通信。
无共享:Actor 之间不共享状态,消除数据竞争。
监督树:层次化的容错机制,自动重启崩溃的进程。
Let it crash:不预防错误,让系统自动恢复。
五、思考与练习
Actor 模型的消息传递和 RPC 有什么区别?
监督树的"one_for_one"和"one_for_all"策略分别适用于什么场景?
用 Actor 模型设计一个简单的分布式任务调度系统。