Несколько синхронизированных функций в одном потоке

1

Я читаю документацию на питон 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)"
Теги:
multithreading
python-2.7
python-multithreading

1 ответ

0

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. Вы говорите о нескольких объектах и трех таймерах за объект, не так ли? Это может показаться не самым элегантным решением, но не похоже, что он перегрузит планировщик.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню