In _run I first set the new timer and then I execute the function. So
that will go mostly OK.
Yes, that's correct however you are not taking into consideration the
imprecision of the timers.
Timer will call the next _run() after self._interval *plus* some unknown
arbitrary time (and extra delay).
Let's assume that when you setup an 1 sec Timer but the Timer calls
_run() after 1.01 secs due this unknown extra delay.
The first time fn() should be called after 1 sec since the begin but it
is called after 1.01 secs so the extra delay was of 0.01 sec.
The second time fn() should be called after 2 secs since the begin but
it is called after 2.02 secs. The second fn() was delayed not by 0.01
but by 0.02 secs.
The third fn() will be delayed by 0.03 secs and so on.
This arbitrary delay is very small however it will sum up on each
iteration and depending of your application can be a serious problem.
I wrote a post about this and how to create "constant rate loops" which
fixes this problem:
https://book-of-gehn.github.io/articles/2019/10/23/Constant-Rate-Loop.html
In the post I also describe two solutions (with their trade-offs) for
when the target function fn() takes longer than the self._interval time.
See if it helps.
Thanks,
Martin.
On Thu, Feb 03, 2022 at 11:41:42PM +0100, Cecil Westerhof via
Python-list wrote:
Barry <ba...@barrys-emacs.org> writes:
On 3 Feb 2022, at 04:45, Cecil Westerhof via Python-list
<python-list@python.org> wrote:
Have to be careful that timing keeps correct when target takes a 'lot'
of time.
Something to ponder about, but can wait.
You have noticed that your class does call the function at the repeat interval
but
rather at the repeat interval plus processing time.
Nope:
def _next(self):
self._timer = Timer(self._interval, self._run)
self._timer.start()
def _run(self):
self._next()
self._fn()
In _run I first set the new timer and then I execute the function. So
that will go mostly OK.
The way to fix this is to subtract the last processing elapsed time for the
next interval.
Sort of a software phase locked loop.
Just before you call the run function record the time.time() as start_time.
Then you can calculate next_interval = max( .001, interval - time.time() -
start_time)
I use 1ms as the min interval.
But I am working on a complete rewrite to create a more efficient
class. (This means I have to change also the code that uses it.) There
I have to do something like you suggest. (I am already working on it.)
Personally I am also of the opinion that the function should finish in
less as 10% from the interval. (That was one of my rewrites.)
--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof
--
https://mail.python.org/mailman/listinfo/python-list
--
https://mail.python.org/mailman/listinfo/python-list