Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast and Precise Python Repeating Timer

I need to send repeating messages from a list quickly and precisely. One list needs to send the messages every 100ms, with a +/- 10ms window. I tried using the code below, but the problem is that the timer waits the 100ms, and then all the computation needs to be done, making the timer fall out of the acceptable window.

Simply decreasing the wait is a messy, and unreliable hack. The there is a Lock around the message loop in the event the list gets edited during the loop.

Thoughts on how to get python to send messages consistently around 100ms? Thanks

from threading import Timer
from threading import Lock

class RepeatingTimer(object):
    def __init__(self,interval, function, *args, **kwargs):
        super(RepeatingTimer, self).__init__()
        self.args = args
        self.kwargs = kwargs
        self.function = function
        self.interval = interval
        self.start()

    def start(self):
        self.callback()

    def stop(self):
        self.interval = False

    def callback(self):
        if self.interval:
            self.function(*self.args, **self.kwargs)
            Timer(self.interval, self.callback, ).start()

def loop(messageList):
    listLock.acquire()
    for m in messageList:
        writeFunction(m)
    listLock.release()


MESSAGE_LIST = [] #Imagine this is populated with the messages
listLock = Lock()
rt = RepeatingTimer(0.1,loop,MESSAGE_LIST)
#Do other stuff after this

I do understand that the writeFunction will cause some delay, but not more than the 10ms allowed. I essentially need to call the function every 100ms for each message. The messagelist is small, usually less than elements.

The next challenge is to have this work with every 10ms, +/-1ms :P

like image 639
dwpriest Avatar asked Mar 23 '13 08:03

dwpriest


People also ask

How do you time accurately in Python?

To measure time with high precision, either use time. clock() or time. time() functions. The python docs state that this function should be used for benchmarking purposes.

How do you call a function repeatedly after a fixed time interval in Python?

Method 1: Using Time Module We will pass the given interval in the time. sleep() function and make while loop is true. The function will sleep for the given time interval. After that, it will start executing.

How do you run a code periodically in Python?

Step 1: Open Task Scheduler Application on your Windows Machine. Step 2: Click on 'Create Basic Task…. ' in the Actions Tab. And give a suitable Name and Description of your task that you want to Automate and click on Next.

How do you make a timer event in Python?

Timer is a sub class of Thread class defined in python. It is started by calling the start() function corresponding to the timer explicitly. Create a timer that will run function with arguments args and keyword arguments kwargs, after interval seconds have passed.


1 Answers

Yes, the simple waiting is messy and there are better alternatives.

First off, you need a high-precision timer in Python. There are a few alternatives and depending on your OS, you might want to choose the most accurate one.

Second, you must be aware of the basics preemptive multitasking and understand that there is no high-precision sleep function, and that its actual resolution will differ from OS to OS too. For example, if we're talking Windows, the minimal sleep interval might be around 10-13 ms.

And third, remember that it's always possible to wait for a very accurate interval of time (assuming you have a high-resolution timer), but with a trade-off of high CPU load. The technique is called busy waiting:

while(True):
    if time.clock() == something:
         break

So, the actual solution is to create a hybrid timer. It will use the regular sleep function to wait the main bulk of the interval, and then it'll start probing the high-precision timer in the loop, while doing the sleep(0) trick. Sleep(0) will (depending on the platform) wait the least possible amount of time, releasing the rest of the remaining time slice to other processes and switching the CPU context. Here is a relevant discussion.

The idea is thoroughly described in the Ryan Geiss's Timing in Win32 article. It's in C and for Windows API, but the basic principles apply here as well.

like image 162
Vladimir Sinenko Avatar answered Oct 06 '22 23:10

Vladimir Sinenko