【问题标题】:How to trigger handle_info due to timeout in erlang?由于erlang超时,如何触发handle_info?
【发布时间】:2020-04-20 21:25:45
【问题描述】:

我正在使用 gen_server 行为,并试图了解如何从 timeout 中触发 handle_info/2,例如:

-module(server).
-export([init/1,handle_call/3,handle_info/2,terminate/2).
-export([start/0,stop/0]).

init(Data)->
    {ok,33}.
start()->
   gen_server:start_link(?MODULE,?MODULE,[]).
stop(Pid)->
   gen_server:stop(Pid).

handle_call(Request,From,State)->
     Return={reply,State,State,5000},
     Return.

handle_info(Request,State)->
    {stop,Reason,State}.

terminate(Reason,State)->
    {ok,S}=file:file_open("D:/Erlang/Supervisor/err.txt",[read,write]),
    io:format(S,"~s~n",[Reason]),
    ok.

我想做的事

我期待如果我启动服务器并且在5 秒内不使用gen_server:call/2(在我的情况下),那么handle_info 将被调用,这又会发出stop 从而调用@987654332 @。 我看到它不会以这种方式发生,实际上handle_info 根本没有被调用。

this 等示例中,我看到timeout 设置在init/1 的返回值中。

我可以推断,只有在我初始化服务器时才会触发handle_info并且什么都不发出(对于 N 秒,cast 也不是 call)。如果是这样,为什么我可以在 returnhandle_cast/2handle_call/3Timeout 中提供 Timeout

更新

我试图获得以下功能:

  1. 如果在X秒内没有发出call,则触发handle_info/2
  2. 如果在Y 秒内没有发出cast,则触发handle_info/2

我以为可以在returnhandle_callhandle_cast 中设置这个超时时间:

{reply,Reply,State,X} //for call
{noreply,State,Y}   //for cast

如果不是,这些超时是什么时候触发的,因为它们是returns

【问题讨论】:

    标签: server erlang timeout erlang-otp


    【解决方案1】:

    我建议你阅读源代码:gen_server.erl

    % gen_server.erl 
    % line 400
    loop(Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug) ->
      Msg = receive
              Input ->
                Input
            after Time ->
          timeout
            end,
      decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, false).
    

    帮助你理解参数Timeout

    【讨论】:

      【解决方案2】:

      要从gen_server:handle_call/3 回调启动超时处理,必须首先调用此回调。你的Return={reply,State,State,5000}, 根本没有被执行。

      相反,如果您想“启动服务器并且在 5 秒内不使用 gen_server:call/2,则将调用 handle_info/2”,您可以从 gen_server:init/1 回调中返回 {ok,State,Timeout} 元组。

      init(Data)->
          {ok,33,5000}.
      

      您不能为不同的调用和强制转换设置不同的超时。正如 Alexey Romanov 在 cmets 中所说,

      对于不同类型的消息具有不同的超时时间并不是任何gen_* 行为都会发生的事情,并且必须通过将它们保持在内部状态来模拟。


      如果从任意handle_call/3/handle_cast/2返回{reply,State,Timeout}元组,则如果Timeout之后该进程的邮箱为空,则会触发超时。

      【讨论】:

      • 我不明白。如果我在init/1 return 中设置了超时,这是否意味着如果我不调用任何东西(在给定的时间间隔内调用或强制转换)它会被触发?如果我想要不调用callcast 的不同超时时间,例如:5000 不调用call3000 不调用cast?还有一次我使用call 并输入handle_call 什么时候触发超时?如果调用者在给定的超时时间内没有得到回复或如何?
      • 我认为这不适用于他的要求(如果 理解正确的话)。取而代之的是,将使用其中一个超时,具体取决于稍后处理 callcast 中的哪一个。对不同类型的消息有不同的超时时间并不是任何gen_* 行为都会发生的事情,并且必须通过将它们保持在内部状态来模拟。
      • 如果从任意handle_call/3/handle_cast/2返回{reply,State,Timeout}元组,如果Timeout之后该进程的邮箱为空,则会触发超时。
      • handle_info/2Request=timeout 如果在超时内没有收到此gen_server 的消息,VM 将调用。
      • 对不起,我不关注。什么“上述”场景? {reply,Reply,State,Timeout}handle_call/3 返回,之后可能不会被调用。如果从 call/2/cast/2 返回任何 {__, Timeout} 元组 并且在 Timeout 中没有消息发送到此进程(阅读:没有 call/cast/! 发出此gen_server 作为接收者,VM 会向其发送消息timeout,可能会使用handle_info(timeout, _State) 处理。
      猜你喜欢
      • 1970-01-01
      • 2011-02-12
      • 2014-05-08
      • 2015-09-25
      • 1970-01-01
      • 2015-07-21
      • 2012-03-22
      • 2022-01-14
      • 2011-05-27
      相关资源
      最近更新 更多