代码之家  ›  专栏  ›  技术社区  ›  offby1

在二郎,定期做些什么是最好的方法?

  •  30
  • offby1  · 技术社区  · 15 年前

    我有一个过程,每15秒需要做一些工作。我现在这样做:

        -behavior(gen_server).
    
        interval_milliseconds ()-> 15000.
        init()->
            {ok, 
             _State = FascinatingStateData,
             _TimeoutInterval = interval_milliseconds ()
            }.
    
        %% This gets called automatically as a result of our handlers
        %% including the optional _TimeoutInterval value in the returned
        %% Result
        handle_info(timeout, StateData)->
            {noreply, 
             _State = do_some_work(StateData),
              _TimeoutInterval = interval_milliseconds ()
            }.
    

    这是可行的,但它非常脆弱:如果我想教我的服务器一条新消息,当我编写任何新的处理程序函数时,我必须记住在其返回值中包含可选的超时间隔。也就是说,如果我正在处理同步调用,我需要这样做:

        %% Someone wants to know our state; tell them
        handle_call(query_state_data, _From, StateData)->
            {reply, StateData, _NewStateData = whatever (), interval_milliseconds ()};
    

    而不是

        %% Someone wants to know our state; tell them
        handle_call(query_state_data, _From, StateData)->
            {reply, StateData, _NewStateData = whatever ()};
    

    你可能猜到了,我犯了很多次错误。这很糟糕,因为一旦代码处理了查询状态数据消息,超时就不再生成,整个服务器就会慢慢停止。(我可以通过在机器上取一个外壳并手动发送“超时”消息来手动“除颤”,但是……EWW)

    现在,我可以尝试记住始终在结果值中指定可选的超时参数。但这并不能说明问题:总有一天我会忘记的,我会再次关注这个bug。那么:更好的方法是什么?

    我不想写一个真正的循环,它永远运行,并且大部分时间都在睡觉;这似乎违背了OTP的精神。

    3 回复  |  直到 11 年前
        1
  •  21
  •   Elzor    11 年前

    最好的方法是:

    init([]) ->
      Timer = erlang:send_after(1, self(), check),
      {ok, Timer}.
    
    handle_info(check, OldTimer) ->
      erlang:cancel_timer(OldTimer),
      do_task(),
      Timer = erlang:send_after(1000, self(), check),
      {noreply, Timer}.
    
        2
  •  38
  •   Andrew    15 年前

    使用 timer :发送间隔/2。例如。:

    -behavior(gen_server).
    
    interval_milliseconds()-> 15000.
    init()->
        timer:send_interval(interval_milliseconds(), interval),
        {ok, FascinatingStateData}.
    
    %% this clause will be called every 15 seconds
    handle_info(interval, StateData)->
        State2 = do_some_work(StateData)
        {noreply, State2}.
    
        3
  •  7
  •   Gordon Guthrie    15 年前

    使用 timer 模块:

    推荐文章