<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Not to keep beating on this, but, one thing I noticed when testing timers in Erlang a couple years ago was that many -closely clumped- timers would lead to skew. That is, apply_interval works cleanly because it only ever has a single timer running, and just calculates how long to sleep for in between each call.</div><div><br></div><div>The problem is trying to create many processes, with timers all having very close together stop times leads to very noticeable drift. The closer they are together, the worse it is (as you noticed in your original question). Having just as many timers, but with greater space between their firing, leads to less drift, and at large enough spacing essentially no drift. </div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
------------------------------<br><br>
Date: Tue, 13 Jan 2015 20:44:09 +1100<br>
From: Bob Ippolito <<a href="mailto:bob@redivi.com" target="_blank">bob@redivi.com</a>><br>
To: Roberto Ostinelli <<a href="mailto:roberto@widetag.com" target="_blank">roberto@widetag.com</a>><br>
Cc: Erlang Questions <<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a>><br>
Subject: Re: [erlang-questions] I'm having a SNAFU moment:<br>
timer:sleep/1<br>
Message-ID:<br>
<<a href="mailto:CACwMPm-sZx9a5ZcF%2Bkh8SE1S3E4r6WYCT8Ch82QHUEFUwt2Y6Q@mail.gmail.com" target="_blank">CACwMPm-sZx9a5ZcF+kh8SE1S3E4r6WYCT8Ch82QHUEFUwt2Y6Q@mail.gmail.com</a>><br>
Content-Type: text/plain; charset="utf-8"<br>
<br>
The implementation of the timer module does rely on the same sleeping<br>
machinery as receive (gen_server timeout) but it doesn't suffer drift by<br>
using the technique that Darach suggested. It keeps track of timers in<br>
terms of absolute time, and when it wakes up it samples the clock to see<br>
which timers need to fire. Nothing special about the timer module, it just<br>
uses a better algorithm... although it is a single gen_server process per<br>
node, so having a lot of timers can be a bottleneck.<br>
<br>
<a href="https://github.com/erlang/otp/blob/maint/lib/stdlib/src/timer.erl#L345-L375" target="_blank">https://github.com/erlang/otp/blob/maint/lib/stdlib/src/timer.erl#L345-L375</a><br>
<br>
On Tue, Jan 13, 2015 at 8:28 PM, Roberto Ostinelli <<a href="mailto:roberto@widetag.com" target="_blank">roberto@widetag.com</a>><br>
wrote:<br>
<br>
> Thank you Imants.<br>
> Indeed, timer:apply_interval/4 actually works perfectly, no timer<br>
> weirdness. I guess the implementation is not depending on the normal<br>
> receive..after..end loop.<br>
><br>
> For others interested, here's a working code example:<br>
><br>
> -module(test).<br>
> -export([call_periodical/2]).<br>
> -export([periodical_fun/1]).<br>
><br>
> call_periodical(Num, IntervalMs) -><br>
> Start = epoch_time_ms(),<br>
> {ok, TRef} = timer:apply_interval(IntervalMs, ?MODULE, periodical_fun,<br>
> [self()]),<br>
> wait(Num),<br>
> io:format("Finished in ~p microseconds.~n", [epoch_time_ms() - Start]),<br>
> timer:cancel(TRef).<br>
><br>
> wait(0) -> ok;<br>
> wait(Num) -><br>
> receive<br>
> ok -> wait(Num - 1);<br>
> _ -> ok<br>
> end.<br>
><br>
> periodical_fun(Pid) -><br>
> Pid ! ok.<br>
><br>
> epoch_time_ms() -><br>
> {Mega, Sec, Micro} = os:timestamp(),<br>
> (Mega * 1000000 + Sec) * 1000 + round(Micro / 1000).<br>
><br>
><br>
> Running it:<br>
><br>
> Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:8:8] [async-threads:10]<br>
> [hipe] [kernel-poll:false] [dtrace]<br>
><br>
> Eshell V6.3 (abort with ^G)<br>
> 1> c(test).<br>
> {ok,test}<br>
> 2> test:call_periodical(1000, 10).<br>
> Finished in 10004 microseconds.<br>
> {ok,cancel}<br>
> 3> test:call_periodical(2000, 10).<br>
> Finished in 20002 microseconds.<br>
> {ok,cancel}<br>
> 4> test:call_periodical(10000, 1).<br>
> Finished in 10002 microseconds.<br>
> {ok,cancel}<br>
> 5> test:call_periodical(20000, 1).<br>
> Finished in 20000 microseconds.<br>
> {ok,cancel}<br>
> 6> test:call_periodical(1000, 1).<br>
> Finished in 1002 microseconds.<br>
> {ok,cancel}<br>
><br>
> Where everything works as expected.<br>
><br>
> Thank you everyone!<br>
><br>
> Best,<br>
> r.<br>
><br>
><br>
> On Mon, Jan 12, 2015 at 6:14 PM, Imants Cekusins <<a href="mailto:imantc@gmail.com" target="_blank">imantc@gmail.com</a>> wrote:<br>
><br>
>> btw CPU looked ok: was spread across cores and did not max out.<br>
>><br>
><br>
><br>
> _______________________________________________<br>
> erlang-questions mailing list<br>
> <a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
> <a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
><br>
><br>
-------------- next part --------------<br>
An HTML attachment was scrubbed...<br>
URL: <<a href="http://erlang.org/pipermail/erlang-questions/attachments/20150113/dc386403/attachment-0001.html" target="_blank">http://erlang.org/pipermail/erlang-questions/attachments/20150113/dc386403/attachment-0001.html</a>><br>
<br>
------------------------------<br>
<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
<br>
<br>
End of erlang-questions Digest, Vol 200, Issue 4<br>
************************************************<br>
</blockquote></div><br></div></div>