执行以下代码时,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模块?
答案 0 :(得分:3)
no_proc - 表示没有进程' - 你还没有启动你的服务器。
Gen_server是OTP架构的一部分。这意味着你需要编写启动supervisor的应用程序来启动你的drop服务器。
然后你可以使用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().