Erlang GenServer #
一、GenServer概述 #
gen_server是Erlang/OTP中最常用的行为,实现了通用的客户端-服务器模式。
1.1 特点 #
- 标准化的服务器接口
- 同步和异步调用
- 状态管理
- 错误处理
- 热代码升级
二、基本结构 #
2.1 完整示例 #
erlang
-module(counter_server).
-behaviour(gen_server).
-export([start_link/0, increment/0, decrement/0, get_count/0, stop/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
increment() ->
gen_server:cast(?SERVER, increment).
decrement() ->
gen_server:cast(?SERVER, decrement).
get_count() ->
gen_server:call(?SERVER, get_count).
stop() ->
gen_server:stop(?SERVER).
init([]) ->
{ok, 0}.
handle_call(get_count, _From, State) ->
{reply, State, State};
handle_call(_Request, _From, State) ->
{reply, {error, unknown_request}, State}.
handle_cast(increment, State) ->
{noreply, State + 1};
handle_cast(decrement, State) ->
{noreply, State - 1};
handle_cast(_Request, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
三、回调函数 #
3.1 init/1 #
erlang
init(Args) ->
State = initialize_state(Args),
{ok, State}.
initialize_state(_Args) -> #{}.
返回值:
{ok, State}- 成功初始化{ok, State, Timeout}- 带超时{ok, State, hibernate}- 休眠{stop, Reason}- 初始化失败ignore- 忽略
3.2 handle_call/3 #
erlang
handle_call({get, Key}, _From, State) ->
Value = maps:get(Key, State, undefined),
{reply, Value, State};
handle_call({set, Key, Value}, _From, State) ->
NewState = State#{Key => Value},
{reply, ok, NewState};
handle_call(stop, _From, State) ->
{stop, normal, ok, State}.
返回值:
{reply, Reply, State}- 返回回复{reply, Reply, State, Timeout}- 带超时{noreply, State}- 不回复{noreply, State, Timeout}- 不回复带超时{stop, Reason, Reply, State}- 停止并回复{stop, Reason, State}- 停止
3.3 handle_cast/2 #
erlang
handle_cast({async_set, Key, Value}, State) ->
NewState = State#{Key => Value},
{noreply, NewState};
handle_cast(stop, State) ->
{stop, normal, State}.
返回值:
{noreply, State}- 继续运行{noreply, State, Timeout}- 带超时{stop, Reason, State}- 停止
3.4 handle_info/2 #
erlang
handle_info({timeout, Ref, Msg}, State) ->
io:format("Timeout: ~p~n", [Msg]),
{noreply, State};
handle_info({'EXIT', Pid, Reason}, State) ->
io:format("Process ~p exited: ~p~n", [Pid, Reason]),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
3.5 terminate/2 #
erlang
terminate(normal, State) ->
io:format("Normal termination~n"),
ok;
terminate(shutdown, State) ->
io:format("Shutdown~n"),
ok;
terminate({shutdown, Reason}, State) ->
io:format("Shutdown: ~p~n", [Reason]),
ok;
terminate(Reason, State) ->
io:format("Abnormal termination: ~p~n", [Reason]),
ok.
3.6 code_change/3 #
erlang
code_change({down, _OldVsn}, State, _Extra) ->
{ok, downgrade_state(State)};
code_change(_OldVsn, State, _Extra) ->
{ok, upgrade_state(State)}.
upgrade_state(State) -> State.
downgrade_state(State) -> State.
四、API设计 #
4.1 同步调用 #
erlang
get_value(Key) ->
gen_server:call(?SERVER, {get, Key}).
set_value(Key, Value) ->
gen_server:call(?SERVER, {set, Key, Value}).
4.2 异步调用 #
erlang
async_set(Key, Value) ->
gen_server:cast(?SERVER, {async_set, Key, Value}).
async_stop() ->
gen_server:cast(?SERVER, stop).
4.3 带超时调用 #
erlang
get_value_with_timeout(Key, Timeout) ->
gen_server:call(?SERVER, {get, Key}, Timeout).
五、状态管理 #
5.1 使用Map #
erlang
-module(map_state_server).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2]).
init(Args) ->
{ok, #{args => Args, count => 0}}.
handle_call({get, Key}, _From, State) ->
{reply, maps:get(Key, State, undefined), State}.
handle_cast({set, Key, Value}, State) ->
{noreply, State#{Key => Value}}.
5.2 使用Record #
erlang
-module(record_state_server).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2]).
-record(state, {name, count = 0, items = []}).
init(Name) ->
{ok, #state{name = Name}}.
handle_call(get_name, _From, State = #state{name = Name}) ->
{reply, Name, State};
handle_call(get_count, _From, State = #state{count = Count}) ->
{reply, Count, State}.
handle_cast(increment, State = #state{count = Count}) ->
{noreply, State#state{count = Count + 1}}.
六、实际应用 #
6.1 缓存服务器 #
erlang
-module(cache_server).
-behaviour(gen_server).
-export([start_link/0, get/1, put/2, delete/1, clear/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
get(Key) ->
gen_server:call(?MODULE, {get, Key}).
put(Key, Value) ->
gen_server:cast(?MODULE, {put, Key, Value}).
delete(Key) ->
gen_server:cast(?MODULE, {delete, Key}).
clear() ->
gen_server:cast(?MODULE, clear).
init([]) ->
{ok, #{}}.
handle_call({get, Key}, _From, State) ->
{reply, maps:get(Key, State, undefined), State}.
handle_cast({put, Key, Value}, State) ->
{noreply, State#{Key => Value}};
handle_cast({delete, Key}, State) ->
{noreply, maps:remove(Key, State)};
handle_cast(clear, _State) ->
{noreply, #{}}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
6.2 连接池 #
erlang
-module(pool_server).
-behaviour(gen_server).
-export([start_link/1, checkout/0, checkin/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link(Size) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [Size], []).
checkout() ->
gen_server:call(?MODULE, checkout).
checkin(Conn) ->
gen_server:cast(?MODULE, {checkin, Conn}).
init([Size]) ->
Connections = [create_connection() || _ <- lists:seq(1, Size)],
{ok, #{available => Connections, busy => []}}.
handle_call(checkout, _From, State = #{available := []}) ->
{reply, {error, no_available_connections}, State};
handle_call(checkout, _From, State = #{available := [Conn | Rest], busy := Busy}) ->
{reply, {ok, Conn}, State#{available => Rest, busy => [Conn | Busy]}}.
handle_cast({checkin, Conn}, State = #{available := Available, busy := Busy}) ->
NewBusy = lists:delete(Conn, Busy),
{noreply, State#{available => [Conn | Available], busy => NewBusy}}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
create_connection() ->
spawn(fun() -> connection_loop() end).
connection_loop() ->
receive
{request, From, Data} ->
From ! {response, Data},
connection_loop()
end.
七、总结 #
本章学习了:
- GenServer概述
- 基本结构
- 回调函数
- API设计
- 状态管理
- 实际应用
准备好学习Supervisor了吗?让我们进入下一章。
最后更新:2026-03-27