Помещение данных в очередь

pomeshhenie dannyh v ochered Приемы программирования графических интерфейсов

Обменивается ли ваш графический интерфейс данными со спутниками, веб-серверами или с чем-то еще, эта многопоточная модель легко воплощается в программный код. В примере 10.18 приводится графический интерфейс, эквивалентный многопоточной программе с очередями, с которой мы встречались в главе 5 (сравните его с примером 5.14). В данном случае графический интерфейс является потоком-потребителем, а потоки-производители добавляют данные для отображения в общую очередь. Для проверки появления результатов в очереди главный поток вместо явного цикла использует метод after из библиотеки.

Пример 10.18. PP4E\Gui\Tools\queuetest-gui.py

#  графический интерфейс, отображающий данные, производимые рабочими потоками

import _thread, queue, time

dataQueue = queue.Queue() # бесконечной длины

def producer(id):

for i in range(5):

time.sleep(0.1) print(‘put’) dataQueue.put(‘[producer id=%d, count=%d]’ % (id, i))

def consumer(root):

try:

print(‘get’)

data = dataQueue.get(block=False)

except queue.Empty:

pass

else:

root.insert(‘end’, ‘consumer got => %s\n’ % str(data)) root.see(‘end’)

root.after(250, lambda: consumer(root)) # 4 раза в секунду

def makethreads():

for i in range(4):

_thread.start_new_thread(producer, (i,))

if __name__ == ‘__main__’:

#  главный поток: порождает группу рабочих потоков на каждый щелчок мыши from tkinter.scrolledtext import ScrolledText root = ScrolledText() root.pack()

root.bind(‘<Button-1>’, lambda event: makethreads()) consumer(root) # запустить цикл проверки очереди в главном потоке окна root.mainloop() # вход в цикл событий

Обратите внимание, что здесь при каждом событии от таймера из очереди извлекается только один элемент данных. Это было сделано сознательно. Можно было бы при каждом событии от таймера извлекать все элементы из очереди в цикле. Но в критических случаях, при наличии большого количества данных в очереди, это легко могло бы привести к блокированию графического интерфейса (представьте быстрый интерфейс телеметрии, который внезапно передал в очередь сразу сотни или даже тысячи результатов измерений). Обрабатывая по одному элементу за раз, мы гарантируем, что цикл событий графического интерфейса будет получать управление, обновлять изображение на экране и обрабатывать ввод пользователя. Недостаток такого подхода состоит в том, что при большом количестве элементов данных в очереди их обработка может занять продолжительное время. В подобных ситуациях можно воспользоваться гибридными схемами, например извлекать из очереди до N элементов данных при каждом событии от таймера, — мы увидим пример реализации такой схемы далее в этом разделе (пример 10.20).

Если запустить этот сценарий, главный поток графического интерфейса начнет извлекать данные из очереди и отображать их в окне ScrolledText, как показано на рис. 10.11. При каждом щелчке левой кнопкой мыши в окне будет запускаться новая группа из четырех потоков- производителей. Потоки выполнения выводят сообщения «get» и «put» в стандартный поток вывода (в данном примере эта операция не синхронизируется между потоками — на некоторых платформах, включая Windows, выводимые сообщения могут перемешиваться). Для имитации выполнения продолжительных операций, таких как получение почты, извлечение результатов запроса или ожидание поступления данных через сокет (дополнительно о сокетах рассказывается ниже в этой главе), потоки-производители вызывают функцию sleep. Я выполнил несколько щелчков левой кнопкой мыши, чтобы обеспечить перекрытие потоков выполнения, как показано на рис. 10.11.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий