为什么Erlang/OTP gen_服务器回调模块必须提供handle_cast功能?

为什么Erlang/OTP gen_服务器回调模块必须提供handle_cast功能?,erlang,otp,gen-server,Erlang,Otp,Gen Server,我能理解为什么回调模块必须提供init和handle\u call函数init用于创建初始状态,而handle\u call是创建服务器进程的主要目的:为请求提供服务 但我不明白为什么需要handle\u cast。难道不能像许多其他回调一样,提供默认的实现吗?这可能是一个像 handle_cast(_, State) -> {noreply, State}. 在我看来,大多数回调模块都提供了这样的noop。类似于handle\u call,用于对正在运行的gen\u服务器进行异步调用(

我能理解为什么回调模块必须提供
init
handle\u call
函数
init
用于创建初始状态,而
handle\u call
是创建服务器进程的主要目的:为请求提供服务

但我不明白为什么需要
handle\u cast
。难道不能像许多其他回调一样,提供默认的实现吗?这可能是一个像

handle_cast(_, State) -> {noreply, State}.
在我看来,大多数回调模块都提供了这样的noop。

类似于
handle\u call
,用于对正在运行的gen\u服务器进行异步调用(调用是同步的)。它为您处理请求,而不是像
呼叫那样回复

gen_call
类似,它可以改变gen_服务器的状态(或保持原样,取决于您的需要和实现)。它还可以停止您的服务器、休眠等,就像您的呼叫一样-请参阅示例和更广泛的解释

正如您在问题中所说,它“可以是一个noop”,但在某些情况下,最好实现并处理对服务器的异步调用

handle_调用是创建服务器进程的主要目的:为请求提供服务

客户机-服务器体系结构可以应用于范围更广的问题,而不仅仅是提供文档的web服务器。一个例子是几个erlang书籍中讨论的频率服务器。客户端可以从服务器请求一个频率来拨打电话,然后客户端必须等待服务器返回一个特定频率,然后才能拨打电话。这是一个典型的
gen\u server:call()
情况:客户端必须等待服务器返回频率,然后才能拨打电话

但是,当客户端使用频率完成时,客户端会向服务器发送一条消息,告诉服务器取消分配频率。在这种情况下,客户端不需要等待服务器的响应,因为客户端甚至不关心服务器的响应是什么。客户端只需要发送deallocate消息,然后客户端就可以继续执行其他代码。服务器有时间时负责处理解除分配消息,然后将频率从“忙”列表移动到“空闲”列表,以便其他客户端可以使用该频率。因此,客户端使用
gen\u server:cast()
向服务器发送解除分配消息

现在,频率服务器的“主要用途”是什么?分配或取消分配频率?如果服务器没有取消分配频率,那么在一定数量的客户端请求之后,就不会有更多的频率可供分配,客户端将收到一条消息说“没有可用的频率”。因此,为了使系统正常工作,释放频率的动作至关重要。换句话说,
handle\u call()
不是服务器的“主要用途”——
handle\u cast()
同样重要——这两个处理程序都需要保持系统尽可能高效地运行

gen_服务器模块不能提供默认的实现,如 您是否需要其他许多回调

为什么您不能创建一个gen_服务器模板,它有一个默认的
handle_cast()
实现?以下是emac的默认gen_服务器模板:

-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
%%%===================================================================

这不是问这种问题的好地方。这里有两个级别的选择:第一个是关于默认行为应该是显式的还是隐式的,OTP团队(在设计gen_服务器时)显然选择了显式的方式(现在可以定义可选回调,但这与您的主张不同);第二个选择是应用程序在发生意外强制转换(您不能阻止模块使用强制转换接口)时应该做什么,忽略它并不总是您想要的(忽略、记录、崩溃?)。也许很有趣,但这不是本论坛的目标。这是一个关于编程框架的问题。问这个问题的正确位置是什么?你的意思是它只是主处理程序的另一个“版本”,经常使用吗?是的,这取决于你的需求和规格。注意:还有,用于处理超时、传入系统消息的。