2011-05-04 49 views

回答

54

您有兩個簡單的選擇,使用timer:send_interval/2erlang:send_after/3send_interval更容易設置,而send_after(當在Erlang模塊中使用時)更加可靠,因爲它是內置函數,請參見Efficiency Guide

使用send_after還可以確保gen_server過程不會過載。如果您使用的是send_interval函數,則無論進程是否可以跟上,都會收到消息。在handle_info返回之前調用send_after,只有在處理完上一個消息後纔會安排一條新消息。如果你想要更準確的時間跟蹤,你仍然可以安排一個send_after動態設置的時間低於?INTERVAL(甚至0)以趕上。

我會建議大意如下的東西在你的gen_server

-define(INTERVAL, 60000). % One minute 

init(Args) -> 
    ... % Start first timer 
    erlang:send_after(?INTERVAL, self(), trigger), 
    ... 

handle_info(trigger, State) -> 
    ... % Do the action 
    ... % Start new timer 
    erlang:send_after(?INTERVAL, self(), trigger), 
    ... 

相反trigger,如果它是需要的,像{trigger, Count}或東西,你可以用一個狀態送東西。

+1

這是偉大的!這正是我目前所做的。謝謝! – 2011-05-04 15:05:54

+0

最終會不會出現這種情況,因爲計時器每6000+ <動作持續時間> ms會觸發? – 2015-08-19 07:26:38

+0

@PatrickOscity當然,它可能。如果你想真的確定,你可以計算出未來的時間來安排它,然後計算確切的毫秒數。 – 2015-08-19 08:33:13

1

在gen_server中實際上有一個內置的機制來完成同樣的事情。 如果gen_server中的init,handle_call,handle_cast或handle_info方法的響應元組的第三個元素是一個整數,則在該時間段之後將以毫秒爲單位發送一個timeout消息...應該使用handle_info處理該消息。例如:

 
init(Args) -> 
    ... % Start first timer 
    {ok, SomeState, 20000}. %% 20000 is the timeout interval 

handle_call(Input, From, State) -> 
    ... % Do something 
    ... % Do something else 
    {reply, SomeState, 20000}. %% 20000 is the timeout interval 

handle_cast(Input, State) -> 
    ... % Do something 
    ... % Do something else 
    {noreply, SomeState, 20000}. %% 20000 is the timeout interval 


%% A timeout message is sent to the gen_server to be handled in handle_info %% 
handle_info(timeout, State) -> 
    ... % Do the action 
    ... % Start new timer 
    {noreply, SomeState, 20000}. %% "timeout" can be sent again after 20000 ms 

+0

爲什麼我得到-1票的任何理由? – 2011-05-05 09:45:23

+0

這是真的。雖然這意味着你必須操縱超時,這可能不是一個壞主意。 – 2011-05-05 09:57:28

+10

'timeout'不適用於定期執行。當這段時間沒有任何事情發生時,它打算髮起一些行動或終止。即使通過某些系統('sys','proc_lib',...)操作,每次操作都會終止該超時。不久之後,使用超時是不鼓勵的依賴,除了一些「維護」的東西,如自動終止或清理。 – 2011-05-05 09:58:26

3

精確控制定時器,你可能需要使用erlang:start_timer,並保存您創建的每個定時器參考。

erlang:start_timererlang:send_after一個微小的差別,看http://www.erlang.org/doc/man/erlang.html#start_timer-3http://www.erlang.org/doc/man/erlang.html#send_after-3

示例使用情形:

init(Args) -> 
    ... 
    TRef = erlang:start_timer(?INTERVAL, self(), trigger), 
    State = #state{tref = TRef}, 
    ... 

handle_info({timeout, _Ref, trigger}, State) -> 
    %% With this cancel call we are able to manually send the 'trigger' message 
    %% to re-align the timer, and prevent accidentally setting duplicate timers 
    erlang:cancel(State#state.tref), 
    ... 
    TRef = erlang:start_timer(?INTERVAL, self(), trigger), 
    NewState = State#state{tref = TRef}, 
    ... 

handle_cast(stop_timer, State) -> 
    TRef = State#state.tref, 
    erlang:cancel(TRef), 

    %% Remove the timeout message that may have been put in our queue just before 
    %% the call to erlang:cancel, so that no timeout message would ever get 
    %% handled after the 'stop_timer' message 
    receive 
     {timeout, TRef, _} -> void 
     after 0 -> void 
    end, 
    ... 
相關問題