![]() |
consumer got => [producer id=2, count=0] consumer got => [producer id=O, count=0] consumer got => [producer id=l, count=0] consumer got => [producer id=3, count=0] consumer got => [producer id=0, count=l] consumer got => [producer id=2, count=l] consumer got => [producer id=3, count=l] consumer got => [producer id=l, count=l] consumer got => [producer id=3, count=0] consumer got => [producer id=l, count=0] consumer got => [producer id=2, count=0] consumer got => [producer id=0, count=0] consumer got => [producer id=2, count=2] consumer got => [producer id=0, count=2] consumer got => [producer id=3, count=2] consumer got => [producer id=l, count=2] consumer got => [producer id=3, count=l] consumer got => [producer id=l, count=l] consumer got => [producer id=0, count=l] consumer got => [producer id=2, count=l] consumer got => [producer id=2, count=0] consumer got => [producer id=l, count=0] consumer got => [producer id=0, count=0] consumer got => [producer id=3, count=0]
Рис. 10.11. Изображение обновляется главным потоком графического интерфейса
стью доступа к информации в объекте, включая очередь. Это позволило перенести очередь и окно из глобальных переменных в атрибуты экземпляра.
Пример 10.19. PP4E\Gui\Tools\queuetest-gui-class.py
# графический интерфейс, отображающий данные, производимые рабочими потоками
# (на основе классов)
import threading, queue, time
# rom tkinter.scrolledtext import ScrolledText # или PP4E.Gui.Tour.scrolledtext
class ThreadGui(ScrolledText):
threadsPerClick = 4
def __init__(self, parent=None):
ScrolledText.__init__(self, parent)
self.pack()
self.dataQueue = queue.Queue() # бесконечной длины
self.bind(‘<Button-1>’, self.makethreads) # по щелчку левой кнопкой self.consumer() # цикл проверки очереди в
# главном потоке выполнения
def producer(self, id):
for i in range(5):
time.sleep(0.1)
self.dataQueue.put(‘[producer id=%d, count=%d]’ % (id, i))
def consumer(self):
try:
data = self.dataQueue.get(block=False)
except queue.Empty:
pass
else:
self.insert(‘end’, ‘consumer got => %s\n’ % str(data)) self.see(‘end’)
self.after(100, self.consumer) # 10 раз в секунду
def makethreads(self, event):
for i in range(self.threadsPerClick): threading.Thread(target=self.producer, args=(i,)).start()
if __name__ == ‘__main__’:
root = ThreadGui() # в главном потоке: создать GUI, запустить цикл таймера root.mainloop() # войти в цикл событий tk
Рассмотрите внимательнее организацию потоков, использование общей очереди и извлечение данных в цикле от таймера, так как с этими приемами мы еще встретимся далее в этой главе, а также в главе 11, в примере программы PyEdit. В программе PyEdit мы будем использовать эти приемы для организации поиска внешних файлов в потоках, чтобы избежать блокирования графического интерфейса и обеспечить возможность одновременного поиска сразу нескольких файлов. Кроме того, мы повторно воспользуемся классической многопоточной моделью произ- водитель/потребитель в более реалистичном примере, представленном далее в этой главе. позволяющей избежать блокирования графического интерфейса, который должен читать данные из стандартного потока ввода, связанного с потоком вывода другой программы.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011