在 Erlang 中定期执行某些操作的最佳方法是什么?
我有一个流程需要每十五秒做一些工作。 我目前正在这样做:
-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 消息,就不再生成超时,并且整个服务器就会停止运行。 (我可以通过在机器上获取外壳并手动发送“超时”消息来手动“除颤”它,但是......呃。)
现在,我可以尝试记住始终在我的结果值中指定可选的超时参数。 但这无法扩展:有一天我会忘记,并且会再次盯着这个错误。 那么:有什么更好的方法呢?
我不认为我想编写一个永远运行的实际循环,并且大部分时间都在睡觉; 这似乎违背了 OTP 的精神。
I have a process that needs to do some work every fifteen seconds. I'm currently doing it like this:
-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 ()
}.
This works, but it's extremely brittle: if I want to teach my server a new message, when I write any new handler function, I have to remember to include the optional timeout interval in its return value. That is, say if I'm handling a synchronous call, I need to do this:
%% Someone wants to know our state; tell them
handle_call(query_state_data, _From, StateData)->
{reply, StateData, _NewStateData = whatever (), interval_milliseconds ()};
instead of
%% Someone wants to know our state; tell them
handle_call(query_state_data, _From, StateData)->
{reply, StateData, _NewStateData = whatever ()};
As you might guess, I've made that very mistake a number of times. It's nasty, because once the code handles that query_state_data message, the timeouts no longer get generated, and the whole server grinds to a halt. (I can "defibrillate" it manually by getting a shell on the machine and sending a "timeout" message by hand, but ... eww.)
Now, I could try to remember to always specify that optional Timeout parameter in my Result value. But that doesn't scale: I'll forget someday, and will be staring at this bug once again. So: what's a better way?
I don't think I want to write an actual loop that runs forever, and spends most of its time sleeping; that seems counter to the spirit of OTP.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 计时器:send_interval/2。 例如:
Use timer:send_interval/2. E.g.:
最好的办法是:
The best way is:
使用 计时器 模块:)
Use the timer module :)