第5章:Erlang(并发编程)
一、导读
1.1 本章学习目标
第5章介绍 Erlang——一门为并发和容错而生的语言。Erlang 由爱立信开发,用于构建电信系统,其核心理念是"Let it crash"——不试图预防错误,而是让系统在错误后自动恢复。
本章的核心学习目标包括:
- 理解 Erlang 的进程模型:轻量级进程、消息传递、无共享
- 掌握"Let it crash"哲学
- 理解 OTP(Open Telecom Platform)框架
- 体验函数式编程在并发中的优势
1.2 为什么本章如此重要
Erlang 的并发模型影响了 Go、Elixir、Akka 等众多现代语言/框架。在多核时代,Erlang 的"每个进程独立、通过消息通信"模型被证明是构建高并发、高可用系统的最佳实践之一。WhatsApp 用 Erlang 支撑了数亿用户的同时在线。
1.3 核心问题引导
Erlang 的进程和操作系统线程有什么本质区别?
"Let it crash"为什么能构建更可靠的系统?
监督树(Supervision Tree)是如何工作的?
消息传递为什么比共享内存更安全?
二、核心概念详解
2.1 进程与消息传递
erlang
% 创建进程
Pid = spawn(fun() ->
receive
{From, Message} ->
From ! {self(), "Hello, " ++ Message}
end
end),
% 发送消息
Pid ! {self(), "World"},
% 接收回复
receive
{Pid, Response} -> io:format("~s~n", [Response])
end.2.2 Let it crash
erlang
% 不试图预防错误,而是让监督者重启
-module(worker).
-export([start/0, loop/0]).
start() -> spawn(fun loop/0).
loop() ->
receive
{do_work, Data} ->
% 如果这里崩溃,监督者会重启
Result = process(Data),
io:format("Result: ~p~n", [Result]),
loop();
stop ->
ok
end.
process(Data) ->
% 可能崩溃的操作
1 / Data.2.3 监督树
erlang
-module(my_supervisor).
-behaviour(supervisor).
init(_) ->
{ok, {
{one_for_one, % 重启策略
5, % 最大重启次数
60}, % 时间窗口(秒)
[
{worker1, {worker, start, []},
permanent, 5000, worker, [worker]}
]
}}.2.4 模式匹配与递归
erlang
% 列表操作
sum([]) -> 0;
sum([H|T]) -> H + sum(T).
% 快速排序
qsort([]) -> [];
qsort([Pivot|Rest]) ->
{Smaller, Larger} = partition(Pivot, Rest, [], []),
qsort(Smaller) ++ [Pivot] ++ qsort(Larger).
partition(_, [], Smaller, Larger) -> {Smaller, Larger};
partition(Pivot, [H|T], Smaller, Larger) ->
case H =< Pivot of
true -> partition(Pivot, T, [H|Smaller], Larger);
false -> partition(Pivot, T, Smaller, [H|Larger])
end.三、实战案例
3.1 案例一:简单的聊天服务器
erlang
-module(chat_server).
-export([start/0, loop/1]).
start() ->
register(chat, spawn(fun() -> loop([]) end)).
loop(Clients) ->
receive
{join, Pid} ->
io:format("Client joined: ~p~n", [Pid]),
loop([Pid | Clients]);
{leave, Pid} ->
io:format("Client left: ~p~n", [Pid]),
loop(Clients -- [Pid]);
{broadcast, From, Message} ->
lists:foreach(
fun(Pid) ->
case Pid =:= From of
true -> ok;
false -> Pid ! {message, From, Message}
end
end,
Clients
),
loop(Clients)
end.四、本章小结
进程模型:轻量级进程、消息传递、无共享状态。
Let it crash:不预防错误,让监督者重启崩溃的进程。
监督树:层次化的进程管理,自动故障恢复。
函数式编程:不可变数据让并发变得简单。
五、思考与练习
Erlang 的消息传递和共享内存并发各有什么优缺点?
"Let it crash"在什么场景下适用?什么场景下不适用?
用 Erlang 的监督树模型设计一个高可用的 Web 服务。