默认情况下,gen_server 调用(和 gen_fsm)的超时时间为 5 秒。如果一个回调函数持续时间过长,那么服务器会崩溃,原因
{timeout,{gen_server,call,[GenServerPid,LastMessage]}}
看来cast函数的超时时间不一样(我猜是因为回调立即返回),但是如果被回调执行阻塞会导致下一次调用失败。
所以我认为这不是一个好主意,除非您的应用程序要求在回调期间有消息很快到达(换句话说,如果您认为缺少第二条消息是一种错误情况)
检查以下代码:
-module (tout).
-behaviour(gen_server).
-define(SERVER, ?MODULE).
%% export interfaces
-export([start_link/0,call/2,cast/2]).
%% export callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%% INTERFACES %%
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
call(Pid,Time) ->
gen_server:call(Pid,{wait,Time}).
cast(Pid,Time) ->
gen_server:cast(Pid,{wait,Time}).
%% CALLBACK FUNCTIONS %%
init([]) ->
{ok, #{}}.
handle_call({wait,Time}, _From, State) ->
timer:sleep(Time),
{reply, done, State};
handle_call(_Request, _From, State) ->
{reply, {error, unknown_call}, State}.
handle_cast({wait,Time}, State) ->
timer:sleep(Time),
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% LOCAL FUNCTIONS %%
Shell 会话:
1> c(tout).
{ok,tout}
2> tout:start_link().
{ok,<0.136.0>}
3> tout:call(tout,500).
done
4> tout:call(tout,5100).
** exception exit: {timeout,{gen_server,call,[tout,{wait,5100}]}}
in function gen_server:call/2 (gen_server.erl, line 204)
5> tout:start_link().
{ok,<0.141.0>}
6> tout:cast(tout,10000).
ok
7> tout:cast(tout,1000).
ok
8> % wait a little .
8> tout:call(tout,100).
done
9> tout:cast(tout,10000).
ok
10> % no wait .
11> tout:call(tout,100).
** exception exit: {timeout,{gen_server,call,[tout,{wait,100}]}}
in function gen_server:call/2 (gen_server.erl, line 204)
12>
[编辑]
是的,gen_fsm 无法进行选择性接收,通常的问题是:
Fsm 处于 state_1 并接收到应该在 state_2 中处理的消息,就在请求转到 state_2 的消息到达之前:
- 第一条消息必须在 state_1 中处理,否则进程崩溃,
- 此消息已从邮箱中删除,并且当 fsm 切换到 state2 时不会出现在此处,因此应用程序必须管理此风险(例如,通过单个进程以正确的顺序发送 2 条消息来避免这种情况) .
这种情况无法通过其中一个回调中的接收块来解决,因为此问题出现在两个回调之间,而进程正在执行 gen_fsm 代码。
我认为这是 R19 中出现的新行为 gen_statem 应该解决的问题之一(不过我读得很快)