单个线程上的多个定时函数

时间:2022-08-17 20:40:02

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.

我正在阅读关于python线程和计时器子类的文档,如果我想在同一个线程上以不同的速率运行两个(或更多)定时类方法,我不太明白它是如何工作的。

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.

例如,我有一个I / O串行设备,我想定期读取(如果有任何数据),从外部模块写入任何输入消息,并定期编写预定义的设备特定心跳消息。这全部包含在自定义类中。 I / O消息存储在两个单独的类队列对象中。

Do I need to create three threading.Timer objects for each function, or can I somehow use one thread that switches?

我是否需要为每个函数创建三个threading.Timer对象,或者我可以以某种方式使用一个切换的线程?

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

1 个解决方案

#1


0  

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.

事实上,它实际上更像是样本代码而不是其他任何东西。其文档中的第二句是“Timer是Thread的子类,因此也可以作为创建自定义线程的示例。”并且线程文档链接到源,您可以看到它是多么简单。


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.

过去在ActiveState配方集合中有一些很好的例子。我不知道如何搜索他们的新回购,但你可以从标签查找开始。

Alternatively, there are a bunch of more powerful schedulers ready to use on PyPI.

或者,有一堆更强大的调度程序可以在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?

或者您可以围绕tick方法重写代码。如果你每20分钟打勾一次,那么每次打勾都会进行读写操作,心跳每50个刻度运行一次,对吗?

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, e.g., you need to worry about not accumulating lag. For example:

但是,在这一点上,编写一个每20ms循环一次而不是使用计时器的函数几乎一样简单。如果您需要担心不会累积延迟,那么扩展起来会容易得多。例如:

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.

现在你可以在一个线程中运行self.ticker。


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.

或者您可以使用多个Timer对象。你说的是每个物体上有少量物体和三个定时器,对吧?它似乎不是最优雅的解决方案,但它不会让调度程序负担过重。

#1


0  

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.

事实上,它实际上更像是样本代码而不是其他任何东西。其文档中的第二句是“Timer是Thread的子类,因此也可以作为创建自定义线程的示例。”并且线程文档链接到源,您可以看到它是多么简单。


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.

过去在ActiveState配方集合中有一些很好的例子。我不知道如何搜索他们的新回购,但你可以从标签查找开始。

Alternatively, there are a bunch of more powerful schedulers ready to use on PyPI.

或者,有一堆更强大的调度程序可以在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?

或者您可以围绕tick方法重写代码。如果你每20分钟打勾一次,那么每次打勾都会进行读写操作,心跳每50个刻度运行一次,对吗?

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, e.g., you need to worry about not accumulating lag. For example:

但是,在这一点上,编写一个每20ms循环一次而不是使用计时器的函数几乎一样简单。如果您需要担心不会累积延迟,那么扩展起来会容易得多。例如:

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.

现在你可以在一个线程中运行self.ticker。


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.

或者您可以使用多个Timer对象。你说的是每个物体上有少量物体和三个定时器,对吧?它似乎不是最优雅的解决方案,但它不会让调度程序负担过重。