Velocity Reviews > How to launch a function at regular time intervals ?

# How to launch a function at regular time intervals ?

David
Guest
Posts: n/a

 08-12-2009
Hi all, I'm trying to launch a function at regular time intervals but
cannot find the way to do it. Here is the code I wrote (time_interval
is a user defined variable in seconds):

while(1)
timestamp=datetime.now()

timestamp_seconds=timestamp.hour*3600+timestamp.mi nute*60+timestamp.second
if timestamp_seconds % time_interval == 0: ****Call Function****

This does not work because during the second at which the condition
holds true, there is time to call the function several times. Since I
want to have this function called only once every x seconds, I tried

if timestamp_seconds % time_interval ==0 & timestamp.microsecond == 0

But it seems this second condition hardly ever happens (i.e. the
timestamp variable is not updated every microsecond, therefore it can
be 9998 then jump directly to 0003 for instance).

Has anyone run into a similar problem (and solved it) ?

Bartosz Wroblewski
Guest
Posts: n/a

 08-12-2009
On Wed, 12 Aug 2009 14:09:29 -0700, David wrote:
>
> Hi all, I'm trying to launch a function at regular time intervals but
> cannot find the way to do it.
>

For what it's worth, here's how I do it:

---------------8<---------------

#!/usr/bin/env python
from time import sleep

interval = 25 #seconds

while not sleep(interval):
f(spam, eggs, knight)

---------------8<---------------

You might want to put the sleep inside an *obviously* infinite loop. Note
that this works best (most accurately) for longer periods. If you need to
account for the time spent in the actual f() calls, plug in a time.time()
call where appropriate.

--
| <")-, | ''The good-enough is the enemy of the excellent.'' - John Miles
| (_==/ |-----------,-----------------------------------------------------
| ='- | Bartosz Wroblewski | bawr from holyhandgrenade.info or int8.org

Dave Angel
Guest
Posts: n/a

 08-13-2009
David wrote:
> Hi all, I'm trying to launch a function at regular time intervals but
> cannot find the way to do it. Here is the code I wrote (time_interval
> is a user defined variable in seconds):
>
> while(1)
> timestamp=datetime.now()
>
> timestamp_seconds=timestamp.hour*3600+timestamp.mi nute*60+timestamp.second
> if timestamp_seconds % time_interval == 0: ****Call Function****
>
> This does not work because during the second at which the condition
> holds true, there is time to call the function several times. Since I
> want to have this function called only once every x seconds, I tried
> to add the following condition:
>
> if timestamp_seconds % time_interval ==0 & timestamp.microsecond == 0
>
> But it seems this second condition hardly ever happens (i.e. the
> timestamp variable is not updated every microsecond, therefore it can
> be 9998 then jump directly to 0003 for instance).
>
> Has anyone run into a similar problem (and solved it) ?
>
>
>

I'm assuming you want to call it every time_interval seconds, on
average, with a little jitter allowed on each call, but keeping correct
long term. In other words, if one call is a little late, you want the
next one to still happen as close to on-time as possible.

The general outline is something like (untested):

times_called = 0 #number of times function has been called
start_time = now
while True:
elapsed = now - start_time
int_elapsed = int(elapsed/time_interval)
for times_called in range(times_called, int_elapsed):
call_the_function()
sleep(time_interval/10) #this might give us 10% jitter,
which is usually fine

DaveA

Dave Angel
Guest
Posts: n/a

 08-13-2009
Grant Edwards wrote:
> On 2009-08-13, Dave Angel <(E-Mail Removed)> wrote:
>
>
>> I'm assuming you want to call it every time_interval seconds, on
>> average, with a little jitter allowed on each call, but keeping correct
>> long term. In other words, if one call is a little late, you want the
>> next one to still happen as close to on-time as possible.
>>
>> The general outline is something like (untested):
>>
>> times_called = 0 #number of times function has been called
>> start_time = now
>> while True:
>> elapsed = now - start_time
>> int_elapsed = int(elapsed/time_interval)
>> for times_called in range(times_called, int_elapsed):
>> call_the_function()
>> sleep(time_interval/10) #this might give us 10% jitter, which is usually fine
>>

>
> I don't understand the reasoning behind the above loop --
> specifically the sleeping of smaller intervals than needed.
>
> Why not something like this:
>
> interval = 5.0 # interval in seconds
> next = time.time()
>
> while True:
> now = time.time()
> if now < next:
> time.sleep(now-next)
> print "call_the_function()"
> next += interval
>
> That will be accurate over the long term with minimal jitter.
>
>
>
>

Two reasons I didn't take an approach like that one.

1) I frequently need to do something else while waiting, so I tend to do
multiple smaller sleeps. As long as each sleep is at least 100ms, the
2) If (occasionally) the function takes longer than the specified
interval time, my approach does catch-up calls so the average remains
the same.

My loop was only a rough outline, and if neither of these considerations
applies, yours is much nicer.

DaveA

David
Guest
Posts: n/a

 08-13-2009
Thanks all for your answers. As suggested by Dave and Frank, I am
indeed looking for the main program to continue running in the
background (I have several functions I want to launch, each at a
predefined time interval). I like Frank's solution, on the paper it
seems it would do what I am looking for, but I cannot succeed in
having it working. I guess I've been stuck with this problem for too
long and can't succeed in using my brain accurately anymore...

I defined the class as defined by Frank, and I then inserted the
following code in a While True loop, without any other code (the idea
is just to test Frank's solution before really using it in my
program):

func = MyFunction()
func.start()

func.stop()
func.join()

However I'm not getting the expected behavior. It's not taking into
account the 30 sec wait, the function is called again and again
without any time interval... Any idea ?

Again, thanks a lot.

MRAB
Guest
Posts: n/a

 08-13-2009
David wrote:
> Thanks all for your answers. As suggested by Dave and Frank, I am
> indeed looking for the main program to continue running in the
> background (I have several functions I want to launch, each at a
> predefined time interval). I like Frank's solution, on the paper it
> seems it would do what I am looking for, but I cannot succeed in
> having it working. I guess I've been stuck with this problem for too
> long and can't succeed in using my brain accurately anymore...
>
> I defined the class as defined by Frank, and I then inserted the
> following code in a While True loop, without any other code (the idea
> is just to test Frank's solution before really using it in my
> program):
>
> func = MyFunction()
> func.start()
>
> func.stop()
> func.join()
>
> However I'm not getting the expected behavior. It's not taking into
> account the 30 sec wait, the function is called again and again
> without any time interval... Any idea ?
>
> Again, thanks a lot.
>

What exactly do you mean by "I then inserted the following code in a
While True loop"? Do you mean you put all four lines in it? If yes,
then you're repeatedly starting then stopping the function.

Dave Angel
Guest
Posts: n/a

 08-13-2009

Grant Edwards wrote:
> <snip>On 2009-08-13, Dave Angel <(E-Mail Removed)> wrote:
>
>> Grant Edwards wrote:
>>
>>> <snip>
>>> interval = 5.0 # interval in seconds
>>> next = time.time()
>>>
>>> while True:
>>> now = time.time()
>>> if now < next:
>>> time.sleep(now-next)
>>> print "call_the_function()"
>>> next += interval
>>>
>>> That will be accurate over the long term with minimal jitter.
>>>
>>>

>> <snip>
>> 2) If (occasionally) the function takes longer than the
>> specified interval time, my approach does catch-up calls so
>> the average remains the same.
>>

>
> I'm still confused -- doesn't mine do that as well?
>
>

Yep. I missed it again. Clearly it does the catchup the next time
around the while loop.

DaveA

Falcolas
Guest
Posts: n/a

 08-13-2009
On Aug 12, 3:09*pm, David <(E-Mail Removed)> wrote:
> Hi all, I'm trying to launch a function at regular time intervals but
> cannot find the way to do it. Here is the code I wrote (time_interval
> is a user defined variable in seconds):
> [snip]
> Has anyone run into a similar problem (and solved it) ?
>

I did - as part of a script where I needed to send load into a system
at a steady rate. I ended up using threading to do the function calls,
since they were not guaranteed to complete before the next interval.

duration_start = time.time()
interval_counter = 0
while time.time() - duration_start < duration:
unimportant#}).start()
interval_counter += 1
time.sleep((duration_start + (interval * interval_counter)) -
time.time())

Executing this loop with a simple echo and time print showed that
there was no creep over time, and the deviation between intervals was
around 1/100th of a second.

I'm fairly sure I'm creating some gnarly memory leaks and such by not
joining spent threads, but it's been a non-issue in my usage. Adding a
list to keep track of the threads and join on complete threads would
be fairly trivial to implement.

I think for simpler applications, using threading.Timer to kick off
the function would work just as well.

~G

Dave Angel
Guest
Posts: n/a

 08-13-2009
David wrote:
> Thanks all for your answers. As suggested by Dave and Frank, I am
> indeed looking for the main program to continue running in the
> background (I have several functions I want to launch, each at a
> predefined time interval). I like Frank's solution, on the paper it
> seems it would do what I am looking for, but I cannot succeed in
> having it working. I guess I've been stuck with this problem for too
> long and can't succeed in using my brain accurately anymore...
>
> I defined the class as defined by Frank, and I then inserted the
> following code in a While True loop, without any other code (the idea
> is just to test Frank's solution before really using it in my
> program):
>
> func = MyFunction()
> func.start()
>
> func.stop()
> func.join()
>
> However I'm not getting the expected behavior. It's not taking into
> account the 30 sec wait, the function is called again and again
> without any time interval... Any idea ?
>
> Again, thanks a lot.
>
>
>

Why don't you include the code you're actually trying, instead of just
trying to describe it. Frank's class didn't call any function, it just
had a place to do it. So we really don't know what you're running, nor

Perhaps a few well placed print statements?

DaveA

David
Guest
Posts: n/a

 08-13-2009
On 13 août, 21:28, Dave Angel <(E-Mail Removed)> wrote:
> David wrote:
> > Thanks all for your answers. As suggested by Dave and Frank, I am
> > indeed looking for the main program to continue running in the
> > background (I have several functions I want to launch, each at a
> > predefined time interval). I like Frank's solution, on the paper it
> > seems it would do what I am looking for, but I cannot succeed in
> > having it working. I guess I've been stuck with this problem for too
> > long and can't succeed in using my brain accurately anymore...

>
> > I defined the class as defined by Frank, and I then inserted the
> > following code in a While True loop, without any other code (the idea
> > is just to test Frank's solution before really using it in my
> > program):

>
> > * * func = MyFunction()
> > * * func.start()

>
> > * * func.stop()
> > * * func.join()

>
> > However I'm not getting the expected behavior. It's not taking into
> > account the 30 sec wait, the function is called again and again
> > without any time interval... Any idea ?

>
> > Again, thanks a lot.

>
> Why don't you include the code you're actually trying, instead of just
> trying to describe it. *Frank's class didn't call any function, it just
> had a place to do it. *So we really don't know what you're running, nor
> what about it is wrong.
>
> Perhaps a few well placed print statements?
>
> DaveA

Yes, I guess it would be more simple. Here is really what I am trying
to do. I simplified the functions, but the purpose is to write some
text in a local file every x seconds (here, I'm just writing the
timestamp, i.e. a string representing the date & time, every 10
seconds) and to transfer this file to a distant server via FTP every y
seconds (20 seconds in the example below). My code is a little bit
more complicated because each time I transfer the file, I delete the
local file which is then recreated when data is written, but for
simplicity I left this out in the code below. So, here is the code
I've been using to test Frank's code. I've been struggling with using
or not a While True loop or not, and everything I try seems to run
into issues.

from datetime import datetime
import ftplib

class CFtpConnection:
"""FTP Connection parameters"""
def __init__(self, host, port, timeout, user, passwd):
self.host = ""
self.port = 21
self.timeout = 60
self.user = ""
self.passwd = ""

"""Write timestamp in a file every 10 seconds in separate

def __init__(self, timestamp):
self.timestamp = timestamp

def run(self):
while not self.event.is_set():
file_handler = open("Test.txt", 'a')
file_handler.write(self.timestamp.strftime("%y%m%d %H%M%S
\n"))
file_handler.close()
self.event.wait(10)

def stop(self):
self.event.set()

"""Transfer timestamp file every 20 seconds in separate thread"""

def __init__(self, ftp_connection):
self.ftp_connection = ftp_connection

def run(self):
while not self.event.is_set():
file_handler = open("Test.txt", 'r')
Ftp_handler = ftplib.FTP('')
Ftp_handler.connect(self.ftp_connection.host,
self.ftp_connection.port, self.ftp_connection.timeout)
self.ftp_connection.passwd)
Ftp_handler.storbinary("STOR Test.txt", file_handler)
file_handler.close()
Ftp_handler.close()
self.event.wait(20)

def stop(self):
self.event.set()

ftp_connection = CFtpConnection("", 21, 60, "", "")
ftp_connection.host = '127.0.0.1'

while(1):
timestamp = datetime.now()
func_store_data = CStoreData(timestamp)
func_store_data.start()

func_transfer_data = CTransferData(ftp_connection)
func_transfer_data.start()

func_store_data.stop()
func_store_data.join()

func_transfer_data.stop()
func_transfer_data.join()