Модуль queue
реализует очереди с несколькими производителями и несколькими потребителями. Это особенно полезно в потоковом программировании, когда информация должна безопасно обмениваться между несколькими потоками. Класс queue.Queue()
в этом модуле реализует всю необходимую семантику блокировки.
Модуль реализует три типа очереди, которые отличаются только порядком, в котором извлекаются записи:
heapq
и сначала извлекается запись с наименьшим значением.Внутренне эти три типа очередей используют блокировки для временного блокирования конкурирующих потоков, однако они не предназначены для обработки повторного входа в поток.
Кроме того, модуль реализует простой тип очереди FIFO - queue.SimpleQueue()
, специфическая реализация которого обеспечивает дополнительные гарантии в обмен на меньшую функциональность.
queue
.Класс queue.Queue()
реализует базовый контейнер типа FIFO - "первым пришел - первым вышел". Элементы добавляются к одному концу очереди с помощью метода put()
, а удаляются с другого конца с помощью метода get()
.
import queue q = queue.Queue() for i in range(5): q.put(i) while not q.empty(): print(q.get(), end=' ') # 0 1 2 3 4
В отличие от стандартной реализации очереди FIFO, в queue.LifoQueue()
используется порядок "последним пришел - первым вышел", который обычно связан со структурой данных стека.
import queue q = queue.LifoQueue() for i in range(5): q.put(i) while not q.empty(): print(q.get(), end=' ') # 4 3 2 1 0
Иногда порядок обработки элементов в очереди должен основываться на характеристиках этих элементов, а не только на порядке их создания или добавления в очередь. Например, задания на печать из финансового отдела могут иметь приоритет над списком заданий из отдела технической поддержки. Класс модуля queue.PriorityQueue()
использует порядок сортировки содержимого очереди, чтобы решить, какой элемент получить.
import functools import queue import threading @functools.total_ordering class Job: def __init__(self, priority, description): self.priority = priority self.description = description return def __eq__(self, other): try: return self.priority == other.priority except AttributeError: return NotImplemented def __lt__(self, other): try: return self.priority < other.priority except AttributeError: return NotImplemented def process_job(q): while True: next_job = q.get() print('Processing job:', next_job.description) q.task_done() q = queue.PriorityQueue() q.put(Job(3, 'Mid-level')) q.put(Job(10, 'Low-level')) q.put(Job(1, 'Important')) workers = [ threading.Thread(target=process_job, args=(q,)), threading.Thread(target=process_job, args=(q,)), ] for w in workers: w.setDaemon(True) w.start() q.join()
Этот пример имеет несколько потоков, потребляющих задания, которые обрабатываются на основе приоритета элементов в очереди на момент вызова get()
. Порядок обработки элементов, добавляемых в очередь во время работы потоков-потребителей, зависит от переключения контекста потока.
Processing job: Important job Processing job: Mid-level job Processing job: Low-level job