Queue.Queue.get: примеры (PYTHON)

Использование метода get из модуля queue в 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: Использование очереди для обмена данными между несколькими производителями и потребителями.

Пример python
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: Обработка данных с таймаутом и проверкой на завершение с помощью специального объекта.

Пример python
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.

Пример python
import queue
pq = queue.PriorityQueue()
pq.put((3, 'Низкий приоритет'))
pq.put((1, 'Высокий приоритет'))
pq.put((2, 'Средний приоритет'))
while not pq.empty():
    print(pq.get())
(1, 'Высокий приоритет')
(2, 'Средний приоритет')
(3, 'Низкий приоритет')

питон queue.Queue.get function comments

En
Queue.Queue.get Remove and return an item from the queue