Теперь вернемся к примеру 5.14. Ниже приводится вывод этого примера после запуска на моем компьютере под управлением Windows. Обратите внимание, что несмотря на автоматическую координацию обмена данными между потоками с помощью очереди, в этом сценарии по-прежнему необходимо использовать блокировку для синхронизации доступа к стандартному потоку вывода — очередь синхронизирует обмен данными, но в некоторых программах все равно может потребоваться использовать блокировки для других целей. Как было показано в предыдущих примерах, если не использовать блокировку safeprint, вывод от разных потоков-потребителей может перемешиваться, поскольку есть вероятность, что поток-потребитель будет приостановлен в процессе выполнения операции вывода:
C:\…\PP4E\System\Threads> |
queuetest.py |
consumer 1 got => [producer |
id=0, count=0] |
consumer 0 got => [producer |
id=0, count=1] |
consumer 1 got => [producer |
id=0, count=2] |
consumer 0 got => [producer |
id=0, count=3] |
consumer 1 got => [producer |
id=1, count=0] |
consumer 1 got => [producer |
id=2, count=0] |
consumer 0 got => [producer |
id=1, count=1] |
consumer 1 got => [producer |
id=3, count=0] |
consumer 0 got => [producer |
id=1, count=2] |
consumer 1 got => [producer |
id=2, count=1] |
consumer 1 got => [producer |
id=1, count=3] |
consumer 1 got => [producer |
id=3, count=1] |
consumer 0 got => [producer |
id=2, count=2] |
consumer 1 got => [producer |
id=2, count=3] |
consumer 1 got => [producer |
id=3, count=2] |
consumer 1 got => [producer |
id=3, count=3] |
Main thread exit
Попробуйте поэкспериментировать с параметрами в начале этого сценария. Единственный потребитель, например, мог бы имитировать главный поток графического интерфейса. Ниже представлен вывод сценария с единственным потребителем — потоки-производители по- прежнему добавляют данные в очередь в достаточно случайном порядке, потому что потоки выполняются параллельно друг с другом и с потоком-потребителем:
C:\…\PP4E\System\Threads> queuetest.py
consumer 0 got => [producer id=0, count=0]
consumer 0 got => [producer id=0, count=1]
consumer 0 got => [producer id=0, count=2]
consumer 0 got => [producer id=0, count=3]
consumer 0 got => [producer id=1, count=0] consumer 0 got => [producer id=2, count=0] consumer 0 got => [producer id=1, count=1] consumer 0 got => [producer id=3, count=0] consumer 0 got => [producer id=1, count=2] consumer 0 got => [producer id=2, count=1] consumer 0 got => [producer id=1, count=3] consumer 0 got => [producer id=3, count=1] consumer 0 got => [producer id=2, count=2] consumer 0 got => [producer id=2, count=3] consumer 0 got => [producer id=3, count=2] consumer 0 got => [producer id=3, count=3] Main thread exit.
Кроме основных особенностей очередей, продемонстрированных в этом сценарии, очереди могут иметь фиксированный или неограниченный размер, а методы get и put могут блокировать или не блокировать вызывающий поток — подробное описание интерфейса очередей вы найдете в руководстве по стандартной библиотеке Python. Однако, поскольку мы только что попробовали сымитировать типичную структуру сценария с графическим интерфейсом, продолжим исследование этого понятия дальше.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011