简体   繁体   中英

Multiple timed functions on a single thread

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM