How to launch a function at regular time intervals ?

D

David

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.minute*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) ?

Thanks for your help
 
B

Bartosz Wroblewski

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.
 
D

Dave Angel

David said:
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.minute*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) ?

Thanks for your help
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
 
D

Dave Angel

Grant said:
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
overhead cost is pretty small.
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
 
D

David

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.
 
M

MRAB

David said:
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.
 
D

Dave Angel

Grant said:
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
 
F

Falcolas

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) ?

Thanks for your help

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:
for thread_count in xrange(numthreads):
threading.Thread(target=exec_thread, kwargs={#snip
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
 
D

Dave Angel

David said:
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
 
D

David

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.

import threading
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 = ""

class CStoreData(threading.Thread):
"""Write timestamp in a file every 10 seconds in separate
thread"""

def __init__(self, timestamp):
threading.Thread.__init__(self)
self.event = threading.Event()
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()

class CTransferData(threading.Thread):
"""Transfer timestamp file every 20 seconds in separate thread"""

def __init__(self, ftp_connection):
threading.Thread.__init__(self)
self.event = threading.Event()
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)
Ftp_handler.login(self.ftp_connection.user,
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'
ftp_connection.user = "admin"
ftp_connection.passwd = "admin"

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()
 
D

David

With your help, Franck, I think I finally got it to work. This is how
I did it:

# In the main program, launch the 2 threads CStoreData and
CTransferData, which will run indefinitely until they are stopped (if
the threads were launched inside the while loop, there would be an
infinitely growing number of threads CStoreData all doing the same
thing, same for CTransferData)

func_store_data = CStoreData()
func_store_data.start()

func_transfer_data = CTransferData()
func_transfer_data.start()

# While loop, just to keep the threads running until they are stopped
at the end of the program. If there wasn't a while loop, the threads
would be stopped right after they are launched. The while loop
separates the "start" of the threads from the "stop" of the threads

while 1
if end_condition: # terminate program
break # break out of while loop

# Stop all running threads at end

func_store_data.stop()
func_store_data.join()

func_transfer_data.stop()
func_transfer_data.join()


Again thanks a lot to all of you for your precious help.

David
 
D

David

With your help, Franck, I think I finally got it to work. This is how
I did it:

# In the main program, launch the 2 threads CStoreData and
CTransferData, which will run indefinitely until they are stopped (if
the threads were launched inside the while loop, there would be an
infinitely growing number of threads CStoreData all doing the same
thing, same for CTransferData)

func_store_data = CStoreData()
func_store_data.start()

func_transfer_data = CTransferData()
func_transfer_data.start()

# While loop, just to keep the threads running until they are stopped
at the end of the program. If there wasn't a while loop, the threads
would be stopped right after they are launched. The while loop
separates the "start" of the threads from the "stop" of the threads

while 1
if end_condition: # terminate program
break # break out of while loop

# Stop all running threads at end

func_store_data.stop()
func_store_data.join()

func_transfer_data.stop()
func_transfer_data.join()


Again thanks a lot to all of you for your precious help.

David
 
D

David

With your help, Franck, I think I finally got it to work. This is how
I did it:

# In the main program, launch the 2 threads CStoreData and
CTransferData, which will run indefinitely until they are stopped (if
the threads were launched inside the while loop, there would be an
infinitely growing number of threads CStoreData all doing the same
thing, same for CTransferData)

func_store_data = CStoreData()
func_store_data.start()

func_transfer_data = CTransferData()
func_transfer_data.start()

# While loop, just to keep the threads running until they are stopped
at the end of the program. If there wasn't a while loop, the threads
would be stopped right after they are launched. The while loop
separates the "start" of the threads from the "stop" of the threads

while 1
if end_condition: # terminate program
break # break out of while loop

# Stop all running threads at end

func_store_data.stop()
func_store_data.join()

func_transfer_data.stop()
func_transfer_data.join()


Again thanks a lot to all of you for your precious help.

David
 
M

MRAB

David said:
With your help, Franck, I think I finally got it to work. This is how
I did it:

# In the main program, launch the 2 threads CStoreData and
CTransferData, which will run indefinitely until they are stopped (if
the threads were launched inside the while loop, there would be an
infinitely growing number of threads CStoreData all doing the same
thing, same for CTransferData)

func_store_data = CStoreData()
func_store_data.start()

func_transfer_data = CTransferData()
func_transfer_data.start()

# While loop, just to keep the threads running until they are stopped
at the end of the program. If there wasn't a while loop, the threads
would be stopped right after they are launched. The while loop
separates the "start" of the threads from the "stop" of the threads

while 1
if end_condition: # terminate program
break # break out of while loop
You might want to insert a sleep or something in there, otherwise you'll
be it'll consume a lot of CPU time doing nothing (a 'busy wait').
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top