来自gen_server的no_proc异常

时间:2014-03-22 10:10:37

标签: erlang 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).

上面的代码有什么问题?编译drop模块后是否需要编译gen_server模块?

3 个答案:

答案 0 :(得分:3)

no_proc - 表示没有进程' - 你还没有启动你的服务器。

Gen_server是OTP架构的一部分。这意味着你需要编写启动supervisor的应用程序来启动你的d​​rop服务器。

然后你可以使用gen_server调用它:call

如果你只需要函数计算速度,你实际上不需要OTP,你可以导出并调用模块中的函数..种类

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

然后调用它

drop:fall_velocity(60)

BTW gen_server模块已在erlang库中编译。

答案 1 :(得分:2)

您正在测试的代码运行正常。正如已经说过的,你需要启动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显示新进程已注册名称丢弃。

命令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

答案 2 :(得分:0)

您需要先启动服务器,然后才能通过gen_server:call/2与其进行互动。

drop:start_link().