我可以理解为什么回调模块必须提供init
和handle_call
功能。 init
用于创建初始状态,handle_call
是创建服务器进程的主要目的:为请求提供服务。
但我不明白为什么handle_cast
是必需的。无法gen_server
模块提供默认实现,就像许多其他回调一样?它可能是一个noop喜欢
handle_cast(_, State) -> {noreply, State}.
在我看来,大多数回调模块都提供像这样的noops。
答案 0 :(得分:1)
和handle_call是创建服务器进程的主要目的:为请求提供服务。
客户端 - 服务器架构可以应用于更广泛的问题,而不仅仅是提供文档的Web服务器。一个例子是几本erlang书中讨论的频率服务器。客户端可以从服务器请求频率进行电话呼叫,然后客户端必须等待服务器在可以进行呼叫之前返回特定频率。这是一种典型的gen_server:call()
情况:客户端必须等待服务器返回频率,然后客户端才能拨打电话。
但是,当客户端使用频率完成时,客户端会向服务器发送一条消息,告知服务器取消分配频率。在这种情况下,客户端不需要等待来自服务器的响应,因为客户端甚至不关心服务器的响应是什么。客户端只需要发送deallocate消息,然后客户端就可以继续执行其他代码。服务器有责任在有时间的情况下处理解除分配消息,然后将频率从忙碌的"列出一个"免费"列表,以便其他客户端可以使用该频率。因此,客户端使用gen_server:cast()
向服务器发送解除分配消息。
现在,"主要目的是什么"频率服务器?分配或取消分配频率?如果服务器没有解除分配频率,那么在一定数量的客户端请求之后,将无法再发送任何频率,客户端将收到一条消息,其中显示“没有可用的频率”#34 ;。因此,为了使系统正常工作,解除频率的行为是至关重要的。换句话说,handle_call()
不是"主要目的"服务器 - handle_cast()
同样重要 - 需要两个处理程序来保持系统尽可能高效地运行。
无法生成gen_server模块,就像它一样提供默认实现 对许多其他回调做了什么?
为什么不能创建gen_server模板,其默认实现为handle_cast()
?这是emac的默认gen_server模板:
-behaviour(gen_server).
%% API
-export([start_link/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @spec handle_call(Request, From, State) ->
%% {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @spec handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================