В качестве примера представьте, что в моем приложении есть датчик температуры, который проверяет температуру в помещении и затем имеет внешний аппаратный интерфейс с кондиционером для регулировки выходной температуры системы HVAC. Это делается простым способом с помощью стека GPIO.
Приложение имеет некоторые действия типа «критических для безопасности», которые оно может выполнять. Существует множество аппаратных блокировок, но я по-прежнему не хочу, чтобы приложение вышло из строя и заставило кондиционер работать на полную мощность и превратить мой теоретический дом в морозильную камеру.
Проблема есть всегда. ....как преобразовать приложение, управляемое событиями графического пользовательского интерфейса, в приложение с графическим интерфейсом, в котором также выполняется еще один цикл без:
- Нарушения конструкции tkinter/tcl путем перестановки всего в «пока (true): делайте что-то» и добавляйте к нему root.update().
- Добавление потоков в приложение, что сложно и потенциально небезопасно
импортировать tkinter как tk
Код: Выделить всё
def main(args):
# Build the UI for the user
root = tk.Tk()
buttonShutDown = tk.Button(root, text="PUSH ME!")#, command=sys.exit(0))
buttonShutDown.pack()
# Go into the method that looks at inputs and outputs
monitorInputsAndActionOutputs(root)
# The main tkinter loop. NOTE, there are about 9000 articles on why you should NOT just shove everyhtnig in a loop and call root.update(). This is the corect way of doing it! Use root.after() calls!
root.mainloop()
def monitorInputsAndActionOutputs(root):
print ("checked the room temperature")
print ("adjusted the airconditioning to make comfy")
root.after(100, monitorInputsAndActionOutputs, root) # readd one event of the monitorInputsAndActionOutputs process to the tkinter / tcl queue
return None
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
Однако я понимаю потенциальная проблема в том, что приложение имеет приличное количество методов, выполняющих различные настройки стиля PID замкнутого цикла (чтение, размышление, изменение, итерация), и я обеспокоен тем, что очередь событий tkinter начнет забиваться обработкой команд after() и вся система либо замедлится, либо полностью сломается, либо заморозит пользовательский интерфейс, либо сочетание всех трех действий.
Поэтому я хочу добавить что-то вроде (грубый пример кода, это, конечно, не работает):
Код: Выделить всё
def (checkQueueDepth):
myQueue = root.getQueueLength()
if(myQueue > 100 items):
doSomethingToAlertSomeone()
deprioritiseNonCriticalEventsTillThingsCalmTFDown()
После долгих поисков < /p>
- Документация tkinter
- Документация TCL/TK
- Исходный код tkinter
- Остальное из stackoverflow
- Интернет
- Холодильник (для перекуса)
Судя по коду tkinter, также не похоже, что существует какой-либо частный метод или объект/переменная, к которому я могу проникнуть через парадную дверь и опросить.
br />В-третьих, единственное «решение», которое кажется, — это потенциально реализовать новую систему уведомлений для TCL, а затем расширить ее функциональность для обеспечения этой функции. Вероятность того, что я это сделаю, равна нулю, у меня нет ни знаний, ни времени, и я бы скорее переписал все свое приложение на другом языке.
Поскольку это невозможно сделать, «правильный» путь, я подумал о том, «мы не собираемся называть это неправильным, но вполне возможно, что это так».
Я придумал что-то вроде этого:
Код: Выделить всё
def checkCodeLoops(root):
# The maximum time we will accept the queue processing to blow out to is 3 seconds.
maxDelayInQueueResponse = datetime.timedelta(seconds = 3)
# Take a note of the time now as well as the last time this method was run
lastCheckTime = checkTime
checkTime = datetime.datetime.now()
# If the time between this invocation of the checkCodeLoops method and the last one is greater than the max allowable time, panic!
if(checkTime - lastCheckTime > maxDelayInQueueResponse):
doSomethingToReduceLoad()
lockUISoUserCantAddMoreWorkToTheQueue()
# reque this method so that we can check again in 100ms (theoretically in 100ms at least - if the queue's flooded then this might never fire)
root.after_idle(100, monitorInputsAndActionOutputs, root)
return None
Поэтому я мог бы изменить его на root.after вместо root.after_idle, и теоретически это помогло бы, но у нас все еще есть проблема с использованием события в очереди, чтобы проверить, не работает ли очередь, что довольно глупо.
Если бы у меня был способ проверить глубину очереди, я мог бы начать внедряйте стратегии контроля нагрузки ДО того, как дело дойдет до стадии паники.
Очень хотелось бы услышать, есть ли у кого-нибудь лучший способ сделать это.
Подробнее здесь: https://stackoverflow.com/questions/785 ... ueue-depth