如何使用Erlang的gen_server定期执行操作?

我想启动一个gen_server,另外,每分钟会执行一个动作。

什么是最好的方式来安排呢?

你有两个简单的select,使用timer:send_interval/2erlang:send_after/3send_interval更容易设置,而send_after (当在Erlang模块中使用时)更加可靠,因为它是一个内置函数,请参见效率指南 。

使用send_after还可以确保gen_server进程不会被重载。 如果使用send_interval函数,则无论进程是否可以跟上,都会收到消息。 在handle_info返回之前调用send_after ,只有在处理完前一个消息之后,才会安排一条新消息。 如果你想更准确的时间跟踪,你仍然可以安排一个send_afterdynamic设置的时间低于?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, Count}或其他。

要精确控制计时器,您可能需要使用erlang:start_timer ,并保存您创build的每个计时器参考。

erlang:start_timererlang:send_after有微小差别,请参阅http://www.erlang.org/doc/man/erlang.html#start_timer-3和http://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, ... 

在gen_server中实际上有一个内置的机制来完成同样的事情。 如果gen_server中的init,handle_call,handle_cast或handle_info方法的响应元组的第三个元素是一个整数,那么timeout消息将以毫秒为单位发送到进程,应该使用handle_info进行处理。 例如:

 init(Args) - >
    ...%启动第一个定时器
    {ok,SomeState,20000}。  %% 20000是超时间隔

 handle_call(Input,From,State) - >
    ... % 做一点事
    ...%做别的事情
    {reply,SomeState,20000}。  %% 20000是超时间隔

 handle_cast(input,状态) - >
    ... % 做一点事
    ...%做别的事情
    {noreply,SomeState,20000}。  %% 20000是超时间隔


 %%超时消息被发送到gen_server以在handle_info %%中处理
 handle_info(timeout,State) - >
    ...执行操作
    ...%启动新的定时器
    {noreply,SomeState,20000}。 可以在20000 ms后再次发送%%“timeout”

Interesting Posts