Я читаю документацию на питон threading
и timer
подкласс, и я не совсем понимаю, как это будет работать, если я хочу, чтобы запустить два (или более) методы приуроченной классы с различной скоростью на одной и ту же тему.
Например, у меня есть последовательное устройство ввода/вывода, которое я хочу периодически читать (если есть какие-либо данные), записывать любые входные сообщения из внешних модулей и периодически записывать предопределенное сообщение о сердцебиении с определенным номером устройства. Все это завершено в пользовательский класс. Сообщения ввода/вывода хранятся в двух отдельных объектах очереди классов.
Нужно ли мне создавать три объекта 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)"
Timer
прост; нет ничего более, чем вы видите. Он запускает один таймер, один раз, занимая целый поток, чтобы сделать это.
На самом деле, это действительно больше, чем образец кода, чем что-либо еще. Второе предложение в его документации: " Timer
является подклассом Thread
и как таковой также служит примером создания пользовательских потоков". И threading
документы обращаются к источнику, и вы можете видеть, насколько это просто.
Не так сложно построить что-то более сложное из этого образца кода.
Раньше были некоторые хорошие примеры в коллекции рецептов ActiveState. Я не знаю, как искать новое репо, но вы можете начать с поиска тегов.
Кроме того, есть несколько более мощных планировщиков, готовых к использованию в PyPI.
Или вы можете переписать свой код вокруг метода tick
. Если вы отмечаете каждые 20 мс, read
и write
пробег на каждом тике, а heartbeat
пробегает каждые 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)
Однако на данный момент почти так же просто написать функцию, которая зацикливает каждые 20 мс вместо использования таймера. И это намного проще расширить, если, например, вам нужно беспокоиться о том, чтобы не накапливать отставание. Например:
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
Теперь вы можете просто запустить self.ticker
в потоке.
Или вы можете просто использовать несколько объектов Timer
. Вы говорите о нескольких объектах и трех таймерах за объект, не так ли? Это может показаться не самым элегантным решением, но не похоже, что он перегрузит планировщик.