【问题标题】:How to run a Erlang Process periodically with Precise Time (i.e. 10ms)如何以精确的时间(即 10 毫秒)定期运行 Erlang 进程
【发布时间】:2016-12-29 11:10:36
【问题描述】:

我想每 10ms 运行一次周期性的 erlang 进程(基于挂钟时间),10ms 应该尽可能准确;实施它的正确方法应该是什么?

【问题讨论】:

标签: timer erlang


【解决方案1】:

如果您想要真正可靠和准确的周期性过程,您应该使用erlang:monotonic_time/0,1 依赖实际的挂钟时间。如果你使用Stratus3Danswer中的方法,你最终会落后。

start_link(Period) when Period > 0, is_integer(Period) ->
  gen_server:start_link({local, ?SERVER}, ?MODULE, Period, []).

...

init(Period) ->
    StartT = erlang:monotonic_time(millisecond),
    self() ! tick,
    {ok, {StartT, Period}}.

...

handle_info(tick, {StartT, Period} = S) ->
    Next = Period - (erlang:monotonic_time(millisecond)-StartT) rem Period,
    _Timer = erlang:send_after(Next, self(), tick),
    do_task(),
    {noreply, S}.

你可以在shell中测试:

spawn(fun() ->
    P = 1000,
    StartT = erlang:monotonic_time(millisecond),
    self() ! tick,
    (fun F() ->
        receive
          tick ->
            Next = P - (erlang:monotonic_time(millisecond)-StartT) rem P,
            erlang:send_after(Next, self(), tick),
            io:format("X~n", []),
            F()
        end
      end)()
  end).

【讨论】:

  • 这种方法的好处是不可避免的小错误不会及时累积。
【解决方案2】:

如果您真的想尽可能精确,并且您确定您的任务所花费的时间将少于您希望它执行的时间间隔,那么您可以有一个长时间运行的进程,而不是每 10 毫秒生成一个进程。 Erlang 可以每 10 毫秒生成一个新进程,但除非有理由不能重用同一个进程,否则通常不值得开销(即使它很少)。

我会在OTP gen_server 中做这样的事情:

-module(periodic_task).

... module exports

start_link() ->
  gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

... Rest of API and other OTP callbacks

init([]) ->
  Timer = erlang:send_after(0, self(), check),
  {ok, Timer}.

handle_info(check, OldTimer) ->
  erlang:cancel_timer(OldTimer),
  Timer = erlang:send_after(10, self(), check),
  do_task(), % A function that executes your task
  {noreply, Timer}.

然后像这样启动 gen_server:

periodic_task:start_link().

只要 gen_server 正在运行(如果它崩溃,父进程也会因为它们被链接),函数do_task/0 将几乎每 10 毫秒执行一次。请注意,这不会完全准确。执行时间会有偏差。实际间隔为 10ms + 收到定时器消息,取消旧定时器,启动新定时器的时间。

如果您想每 10 毫秒启动一个单独的进程,您可以让 do_task/0 生成一个进程。请注意,这会增加额外的开销,但不一定会降低生成间隔的准确性。

我的例子取自这个答案:What's the best way to do something periodically in Erlang?

【讨论】:

    猜你喜欢
    • 2015-09-13
    • 1970-01-01
    • 2015-09-23
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 2017-08-31
    • 2019-12-07
    相关资源
    最近更新 更多