а handle_call — основная цель создания серверного процесса: обслуживать запросы.
Архитектура клиент-сервер может быть применена к гораздо более широкому кругу задач, чем просто веб-сервер, обслуживающий документы. Одним из примеров является частотный сервер, обсуждаемый в нескольких книгах по erlang. Клиент может запросить у сервера частоту для совершения телефонного звонка, затем клиент должен дождаться, пока сервер вернет определенную частоту, прежде чем можно будет сделать вызов. Это классическая gen_server:call()
ситуация: клиент должен дождаться, пока сервер вернет частоту, прежде чем клиент сможет сделать телефонный звонок.
Однако, когда клиент заканчивает использовать частоту, клиент отправляет сообщение на сервер, говоря серверу освободить частоту. В этом случае клиенту не нужно ждать ответа от сервера, потому что клиенту все равно, какой ответ сервера. Клиенту просто нужно отправить сообщение об освобождении, после чего клиент может продолжить выполнение другого кода. Сервер отвечает за обработку сообщения об освобождении, когда у него есть время, а затем перемещает частоту из списка «занято» в список «свободно», чтобы частота была доступна для использования другими клиентами. В результате клиент использует gen_server:cast()
для отправки сообщения об освобождении на сервер.
Итак, какова «основная цель» частотного сервера? Выделить или освободить частоты? Если сервер не освобождает частоты, то после определенного количества клиентских запросов частот для раздачи больше не будет, и клиенты получат сообщение о том, что «частоты недоступны». Таким образом, для правильной работы системы акт освобождения частот имеет важное значение. Другими словами, handle_call()
не является «основной целью» сервера — handle_cast()
одинаково важен — и оба обработчика необходимы для поддержания максимально эффективной работы системы.
Не может ли модуль gen_server предоставить реализацию по умолчанию, как это делается для многих других обратных вызовов?
Почему вы не можете сами создать шаблон gen_server, который имеет реализацию handle_cast()
по умолчанию? Вот шаблон gen_server по умолчанию для emac:
-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
%%%===================================================================
person
7stud
schedule
08.05.2018