I am reading the docs on python threading
and the timer
subclass and I do not quite understand how it would work if I want to run two (or more) timed class methods at different rates on the same thread.
For example, I have an I/O serial device that I want to periodically read (if any data), write any input messages from outside modules, and periodically write a predefined device specific heartbeat message. This is all wrapped in a custom class. I/O messages are stored in two separate class queue objects.
Do I need to create three threading.Timer
objects for each function, or can I somehow use one thread that switches?
import serial, threading, Queue
# the exact syntax below may be incorrect
class MySerialDevice:
def __init__():
# Some other modules will be appending to this (through a class method)
self.write_queue = Queue()
self.read_queue = Queue()
self.port = serial.Serial()
# check for incoming data every 20ms
self.thread1 = threading.Timer(0.02, self.read)
# check for outgoing data every 20ms
self.thread2 = threading.Timer(0.02, self.write)
# Send the heaertbeat every 1 second
self.thread3 = threading.Timer(1, self.heartbeat)
# what do I do here???
# can I make all three tasks on a single thread, that just continuously loops
# and "if incoming data, read, if outgoing data, write, heartbeat???
def read(self):
# checks for actual data, appending to queue are ommited
self.port.read()
def write(self):
# checks for data in queue ommitted
self.port.write(self.write_queue[0])
def heartbeat(self):
self.port.write("Device Heartbeat message)"
Timer
is dead-simple; there's nothing more to it than you see. It runs a single timer, one time, taking up a whole thread to do it.
In fact, it's really there more as sample code than anything else. The second sentence in its documentation is " Timer
is a subclass of Thread
and as such also functions as an example of creating custom threads." And the threading
docs link to the source , and you can see how simple it is.
It's not that hard to build something more complicated out of that sample code.
There used to be some good examples in the ActiveState recipe collection. I don't know how to search their new repo, but you can start off with a tag lookup .
Alternatively, there are a bunch of more powerful schedulers ready to use on PyPI.
Or you can rewrite your code around a tick
method. If you tick every 20ms, read
and write
run on every tick, and heartbeat
runs every 50 ticks, right?
def __init__(self):
self.tickcount = 0
self.timer = threading.Timer(0.02, self.tick)
def tick(self):
self.read()
self.write()
self.tickcount += 20
if not self.tickcount % 1000:
self.heartbeat()
self.timer = threading.Timer(0.02, self.tick)
However, at this point, it's almost as simple to just write a function that loops every 20ms instead of using a timer. And that's much easier to extend if, eg, you need to worry about not accumulating lag. For example:
def ticker(self):
last = datetime.datetime.now()
while True:
wake = last + datetime.timedelta(milliseconds=20)
now = datetime.datetime.now()
while wake > now:
time.sleep((wake - now).total_seconds())
self.tick()
last = wake
Now you can just run self.ticker
in a thread.
Or you can just use multiple Timer
objects. You're talking about a handful of objects and three timers per object, right? It may not seem the most elegant solution, but it's not like it's going to overburden the scheduler.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.