当前位置:  开发笔记 > 编程语言 > 正文

在Erlang中定期做某事的最佳方法是什么?

如何解决《在Erlang中定期做某事的最佳方法是什么?》经验,为你挑选了3个好方法。

我有一个过程需要每十五秒做一些工作.我现在这样做:

    -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 ()};

正如你可能猜到的那样,我多次犯了这个错误.这很讨厌,因为一旦代码处理了query_state_data消息,就不再生成超时,并且整个服务器都会停止运行.(我可以通过在机器上获取一个shell并手动发送"超时"消息来手动"除颤"它,但是...... eww.)

现在,我可以尝试记住始终在Result值中指定可选的Timeout参数.但这不会扩展:我有一天会忘记,并会再次盯着这个错误.那么:什么是更好的方式?

我不认为我想写一个永远运行的实际循环,并且大部分时间都在睡觉; 这似乎与OTP的精神背道而驰.



1> gleber..:

使用timer:send_interval/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}.


我选择使用erlang:send_after,而不是timer:send_interval,我认为解释原因很有启发性.这是因为我的handle_info可能需要很长时间才能完成,当下一个时间间隔到来时它仍然在运行,我不希望超时消息堆积在队列中.通过使用erlang:send_after(一次在init函数中,再一次在handle_info(timeout,...)函数的末尾),我可以确保每个超时在前一个超时之后_at_interval_millisems.这可能不适合所有人,但对我来说似乎是对的.

2> 小智..:

最好的方法是:

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}.



3> Gordon Guthr..:

使用计时器模块:)

推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有