исключение no_proc из gen_server

при выполнении кода ниже gen_server вызывает исключение

    -module(drop).

    -behaviour(gen_server).

    -export([start_link/0]).

    -export([init/1,
     handle_call/3,
     handle_cast/2,
     handle_info/2,
     terminate/2,
     code_change/3]).

   -define(SERVER, ?MODULE).

   -record(state, {count}).

    start_link() -> 
          gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

    init([]) ->
         {ok, #state{count=0}}.

    handle_call(_Request, _From, State) ->
      Distance = _Request,
      Reply = {ok, fall_velocity(Distance)},
      NewState=#state{ count= State#state.count+1},
      {reply, Reply, NewState}.

    handle_cast(_Msg, State) ->
      io:format("so far, calculated ~w velocities.~n", [State#state.count]),
      {noreply, State}.

    handle_info(_Info, State) ->
      {noreply, State}.

    terminate(_Reason, _State) ->
        ok.  

    code_change(_OldVsn, State, _Extra) ->
            {ok, State}.

    fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).   

ВЫХОД:

1> gen_server:call(drop, 60).
** exception exit: {noproc,{gen_server,call,[drop,60]}}
in function  gen_server:call/2 (gen_server.erl, line 180).

Что не так в приведенном выше коде? Нужно ли компилировать модуль gen_server после компиляции модуля drop?


person user3382006    schedule 22.03.2014    source источник
comment
Пожалуйста, ответьте мне, я новичок в языке Erlang, и каждый раз, когда повторяется одна и та же проблема, любая помощь будет оценена по достоинству.   -  person user3382006    schedule 22.03.2014


Ответы (3)


Код, который вы тестируете, работает нормально. Как уже было сказано, вам нужно запустить файл gen_server. Вот как это сделать, а затем задайте запрос:

1> c(drop).
{ok,drop}
2> S = spawn(drop,start_link,[]).
<0.40.0>
3> registered().
[rex,net_sup,inet_db,kernel_sup,global_name_server,
 code_server,file_server_2,init,kernel_safe_sup,
 application_controller,user,error_logger,user_drv,
 standard_error,global_group,standard_error_sup,drop,auth,
 erl_epmd,net_kernel,erl_prim_loader]
4> gen_server:call(drop,25).     
{ok,22.135943621178658}
5> gen_server:call(drop,13).
{ok,15.962455951387932}
6> gen_server:call(drop,20).
{ok,19.79898987322333}
7> gen_server:cast(drop,what).
so far, calculated 3 velocities.
ok

команда 1 компилирует модуль. Нет необходимости компилировать gen_server, это уже сделано в библиотеках Erlang.

команда 2 запускает gen_server, как правило, в модуле, таком как drop, вы добавляете некоторую функцию интерфейса, которая скрывает этот вызов, что-то вроде start() -> spawn(?MODULE,start_link,[])., чтобы вы могли запустить сервер с помощью простого вызова drop:start()

команда 3 показывает, что новый процесс зарегистрирован с именем drop.

команды 4,5 и 6 запрашивают оценку скорости. Что касается начала, использование должно иметь функцию интерфейса, такую ​​​​как velocity(N) -> gen_server:call(?MODULE,N), чтобы вы могли просто call drop:velocity(25) использовать также для «украшения» сообщения, чтобы вы могли иметь больше функций позже.

команда 7 использует приведение сообщения, чтобы получить число скоростей, оцененных на данный момент. То же замечание по поводу интерфейса и оформления. вот версия, более подходящая для использования:

-module(drop).

-behaviour(gen_server).

%% interfaces
-export([start_link/0,velocity/1,so_far/0]).

-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).

-define(SERVER, ?MODULE).

-record(state, {count}).

%% interfaces

start_link() -> 
    spawn (gen_server,start_link,[{local, ?SERVER}, ?MODULE, [], []]).

velocity(N) ->
  gen_server:call(?MODULE,{get_velocity,N}).

so_far() ->
  gen_server:cast(?MODULE,so_far). 

%% call back

init([]) ->
   {ok, #state{count=0}}.

handle_call({get_velocity,Distance}, _From, State) ->
  Reply = {ok, fall_velocity(Distance)},
  NewState=#state{ count= State#state.count+1},
  {reply, Reply, NewState};

handle_call(Request, _From, State) ->
  Reply = io:format("unknown request ~p~n",[Request]),
  {reply, Reply, State}.

handle_cast(so_far, State) ->
  io:format("so far, calculated ~w velocities.~n", [State#state.count]),
  {noreply, State};

handle_cast(Msg, State) ->
  io:format("unknown request ~p~n", [Msg]),
  {noreply, State}.

handle_info(_Info, State) ->
  {noreply, State}.

terminate(_Reason, _State) ->
  ok.  

code_change(_OldVsn, State, _Extra) ->
  {ok, State}.

fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).   

и теперь команды выглядят проще:

12> drop:start_link().
<0.60.0>
13> drop:velocity(25).
{ok,22.135943621178658}
14> drop:velocity(20).
{ok,19.79898987322333}
15> drop:velocity(13).
{ok,15.962455951387932}
16> drop:so_far().    
so far, calculated 3 velocities.
ok
person Pascal    schedule 23.03.2014

no_proc -- означает "нет процесса" -- вы не запустили свой сервер.

Gen_server является частью архитектуры OTP. Это означает, что вам нужно написать приложение, которое запускает супервизор, который запускает ваш удаленный сервер.

И затем вы можете вызвать его, используя gen_server:call

Если вам нужна просто функция для расчета скорости, вам на самом деле не нужен OTP, вы можете экспортировать и вызывать функцию в модуле.

-module(drop).
-export([fall_velocity/1]).
 .....

а затем вызвать его

drop:fall_velocity(60).

Кстати, модуль gen_server уже скомпилирован в библиотеках erlang.

person Odobenus Rosmarus    schedule 22.03.2014

Вам необходимо запустить сервер, прежде чем вы сможете взаимодействовать с ним через gen_server:call/2.

drop:start_link().
person Roberto Aloi    schedule 22.03.2014