Queue.Queue.get: примеры (PYTHON)
queue.Queue.get(block: bool = True, timeout: float = None): AnyФункция queue.Queue.get в Python
Метод get класса Queue из модуля queue предназначен для извлечения и удаления элемента из очереди. Его основное применение связано с многопоточным программированием, где очередь служит безопасным механизмом обмена данными между потоками.
Сигнатура метода: Queue.get(block=True, timeout=None).
Аргументы метода:
- block (логический, по умолчанию True): Определяет поведение метода при пустой очереди. Если установлено True, вызов блокирует выполнение потока до момента появления элемента в очереди или до истечения таймаута. При значении False метод не блокируется и немедленно поднимает исключение queue.Empty, если очередь пуста.
- timeout (положительное число с плавающей точкой или None, по умолчанию None): Максимальное время ожидания в секундах, пока элемент не появится в очереди. Используется только при block=True. Значение None означает неограниченное ожидание.
Возвращаемое значение: элемент, извлеченный из головы очереди. Порядок извлечения соответствует типу очереди (FIFO для Queue, LIFO для LifoQueue, по приоритету для PriorityQueue).
Короткие примеры использования
Пример 1: Базовое извлечение с блокировкой.
import queue
q = queue.Queue()
q.put('Первый элемент')
item = q.get()
print(item)Первый элемент
Пример 2: Извлечение с таймаутом.
import queue
import time
q = queue.Queue()
start = time.time()
try:
item = q.get(timeout=2.0)
except queue.Empty:
print(f'Очередь пуста. Прошло {time.time() - start:.2f} сек.')Очередь пуста. Прошло 2.00 сек.
Пример 3: Немедленное извлечение без блокировки.
import queue
q = queue.Queue()
try:
item = q.get(block=False)
except queue.Empty:
print('Невозможно получить элемент, очередь пуста.')Невозможно получить элемент, очередь пуста.
Похожие функции в Python
Queue.get_nowait(): Эквивалент вызова get(block=False). Позволяет получить элемент без блокировки, немедленно вызывая исключение queue.Empty при пустой очереди. Удобен для краткой записи.
Queue.get(block=True, timeout=0): При установке timeout=0 поведение похоже на get_nowait(), но таймаут с нулевым значением часто более явно указывает на намерение не ждать.
deque.popleft(): Метод коллекции deque из модуля collections. Удаляет и возвращает элемент с левого конца двусторонней очереди. Не является потокобезопасным, но работает быстрее для однопоточных сценариев. Не поддерживает блокировку или таймауты.
Выбор зависит от контекста: Queue.get используют в многопоточных программах для безопасной коммуникации. deque.popleft подходит для высокопроизводительных однопоточных алгоритмов.
Аналоги в других языках программирования
Java (java.util.concurrent.BlockingQueue): Метод take() блокирует поток, а poll(timeout, unit) ожидает указанное время.
BlockingQueue q = new LinkedBlockingQueue<>();
q.put("Элемент");
String item = q.take(); // Блокировка
String item2 = q.poll(2, TimeUnit.SECONDS); // Таймаут JavaScript (Node.js с библиотекой 'async') или каналы в Go: В JavaScript нет встроенной потокобезопасной очереди. Используют массивы с мьютексами или асинхронные очереди из библиотек. В Go для общения между горутинами применяют каналы: <- ch для получения.
ch := make(chan string, 1)
ch <- "сообщение"
msg := <- ch // Блокировка горутиныC# (System.Collections.Concurrent.BlockingCollection): Метод Take() блокируется, а TryTake(out item, timeout) ожидает с таймаутом.
BlockingCollection col = new BlockingCollection();
col.Add("данные");
string data = col.Take(); // Блокировка Основное отличие Python - наличие единого метода get с гибкими параметрами, тогда как в других языках часто используют отдельные методы для разных режимов.
Типичные ошибки при использовании
Ошибка 1: Игнорирование исключения queue.Empty при использовании block=False или timeout.
import queue
q = queue.Queue()
item = q.get(block=False) # Вызовет исключение, если очередь пуста
print(item)Traceback (most recent call last): File "", line 1, in queue.Empty
Ошибка 2: Ожидание получения элемента из очереди, в которую никто не кладет данные, приводящее к вечной блокировке при отсутствии таймаута.
import queue
from threading import Thread
q = queue.Queue()
def consumer():
print(q.get()) # Поток заблокируется навсегда
Thread(target=consumer).start()
# Нет кода, который бы положил элемент в qПоток consumer никогда не завершится.
Ошибка 3: Использование отрицательного значения для timeout.
import queue
q = queue.Queue()
item = q.get(timeout=-1) # Неверное значение таймаутаTraceback (most recent call last): File "", line 1, in ValueError: 'timeout' must be a non-negative number
Изменения в последних версиях
В Python 3.7 был добавлен параметр timeout для методов Queue.get и Queue.put как позиционно-ключевой аргумент. Ранее его можно было передать только как именованный аргумент.
Начиная с Python 3.0, модуль queue (ранее Queue в Python 2) был переименован и стал частью стандартной библиотеки для многопоточного программирования. Поведение метода get осталось стабильным.
В Python 3.2 была улучшена внутренняя реализация примитивов синхронизации, что могло незначительно повлиять на производительность в высоконагруженных сценариях, но интерфейс метода не изменился.
Расширенные примеры использования
Пример 1: Использование очереди для обмена данными между несколькими производителями и потребителями.
import queue, threading, time
q = queue.Queue()
def producer(id):
for i in range(3):
time.sleep(0.1)
q.put(f'Сообщение {i} от {id}')
def consumer(id):
while True:
item = q.get()
if item is None: # Сигнал завершения
q.put(None) # Передаем следующему потребителю
print(f'Потребитель {id} завершает работу.')
break
print(f'Потребитель {id} получил: {item}')
q.task_done()
# Запуск потоков
prod_threads = [threading.Thread(target=producer, args=(i,)) for i in range(2)]
cons_threads = [threading.Thread(target=consumer, args=(i,)) for i in range(3)]
for t in prod_threads: t.start()
for t in cons_threads: t.start()
for t in prod_threads: t.join()
q.put(None) # Сигнал завершения для одного потребителя
for t in cons_threads: t.join()Потребитель 0 получил: Сообщение 0 от 0 Потребитель 1 получил: Сообщение 0 от 1 ... Потребитель 2 завершает работу.
Пример 2: Обработка данных с таймаутом и проверкой на завершение с помощью специального объекта.
import queue, threading
class Sentinel: pass # Объект-сигнал
work_queue = queue.Queue()
def worker():
while True:
try:
task = work_queue.get(timeout=5.0)
if isinstance(task, Sentinel):
print('Рабочий поток получил сигнал завершения.')
work_queue.task_done()
break
print(f'Обработка задачи: {task}')
work_queue.task_done()
except queue.Empty:
print('Таймаут ожидания задачи, повторная проверка.')
threading.Thread(target=worker).start()
work_queue.put('Задача 1')
work_queue.put(Sentinel())Обработка задачи: Задача 1 Рабочий поток получил сигнал завершения.
Пример 3: Использование приоритетной очереди PriorityQueue.
import queue
pq = queue.PriorityQueue()
pq.put((3, 'Низкий приоритет'))
pq.put((1, 'Высокий приоритет'))
pq.put((2, 'Средний приоритет'))
while not pq.empty():
print(pq.get())(1, 'Высокий приоритет') (2, 'Средний приоритет') (3, 'Низкий приоритет')