Кратко проанализируйте четыре вида очередей в Python.

задняя часть Python GitHub Безопасность

Очередь — это линейный список, который позволяет вставлять только на одном конце и удалять на другом.

Поиск очередей в документации Python обнаружит, что в стандартной библиотеке Python есть четыре типа очередей, а именно queue.Queue / asyncio.Queue / multiprocessing.Queue / collections.deque.

collections.deque

Deque — это сокращение от двусторонней очереди.Поскольку оба конца можно редактировать, deque можно использовать для реализации стека или очереди.

deque поддерживает множество методов работы, основные из которых показаны на рисунке:

По сравнению с очередью, реализованной списком, реализация deque имеет меньшую временную и пространственную сложность. Пространственная сложность реализации списка составляет около O (n) при извлечении и вставке, а временная сложность deque составляет O (1) при извлечении и добавлении.

deque также поддерживает оператор in, который можно записать следующим образом:

q = collections.deque([1, 2, 3, 4])
print(5 in q)  # False
print(1 in q)  # True

deque также инкапсулирует метод вращения по часовой стрелке и против часовой стрелки: rotate.

# 顺时针
q = collections.deque([1, 2, 3, 4])
q.rotate(1)
print(q)  # [4, 1, 2, 3]
q.rotate(1)
print(q)  # [3, 4, 1, 2]

# 逆时针
q = collections.deque([1, 2, 3, 4])
q.rotate(-1)
print(q)  # [2, 3, 4, 1]
q.rotate(-1)
print(q)  # [3, 4, 1, 2]

С точки зрения безопасности потоков, просмотрев исходный код таких методов, как append() и pop() в collections.deque, вы можете узнать, что все они являются атомарными операциями, поэтому они являются потокобезопасными методами под защитой GIL. .

static PyObject *
deque_append(dequeobject *deque, PyObject *item) { 
    Py_INCREF(item);
    if (deque_append_internal(deque, item, deque->maxlen) < 0) 
        return NULL;
    Py_RETURN_NONE;
}

Как видно из метода dis, append — это атомарная операция (одна строка байт-кода).

Подводя итог, можно сказать, что collections.deque — это структура данных, которая может легко реализовать очереди, с характеристиками потокобезопасности и высокой производительностью.

queue.Queue & asyncio.Queue

И queue.Queue, и asyncio.Queue — это очереди, поддерживающие несколько производителей и потребителей. На основе collections.deque они обе предоставляют Queue (очередь FIFO), PriorityQueue (очередь с приоритетом), LifoQueue (очередь LIFO) и аспекты интерфейса. такой же.

Разница в том, что queue.Queue подходит для многопоточных сценариев, а asyncio.Queue подходит для взаимодействия в сценариях сопрограммы.Из-за добавления asyncio блокирующий интерфейс очереди.Queue возвращает объекты сопрограммы в asyncio.Queue. конкретные отличия заключаются в следующем:

queue.Queue asyncio.Queue
вводить очередь синхронизации асинхронная очередь
потокобезопасность да нет
механизм тайм-аута Реализуется параметром таймаута Реализован методом asyncio.wait_for().
qsize() Предполагаемая длина очереди (между получением qsize и следующей операцией очередь может быть изменена другими потоками, что приведет к изменению размера qsize) Точная длина очереди (поскольку это один поток, очередь не будет изменена другими потоками)
put() / set() put(item, block=True, timeout=None), вы можете настроить, будут ли методы put и set блокировать, установив, является ли блок True, и вы можете установить максимальную продолжительность тайм-аута для операции блокировки, поведения и put_nowait () когда блок имеет значение False Consistent. Метод put() вернет объект сопрограммы, поэтому параметры блока и параметры тайм-аута отсутствуют.Если вам нужен неблокирующий метод, вы можете использовать put_nowait(), а если вам нужно применить тайм-аут к блокирующему методу, вы можете использовать сопрограмму asyncio.wait_for().

multiprocessing.Queue

Многопроцессорность предоставляет три очереди, а именно Queue, SimpleQueue и JoinableQueue.

multiprocessing.Queue безопасен как для потоков, так и для процессов, что эквивалентно многопроцессорному клону queue.Queue. Подобно threading.Queue, multiprocessing.Queue поддерживает операции ввода и вывода, а базовая структура — multiprocessing.Pipe.

Нижний уровень multiprocessing.Queue построен на основе Pipe, но передача данных не записывается напрямую в Pipe, а записывается в локальный буфер процесса и записывается в нижележащий Pipe через поток фидера.Это необходимо для контроля тайм-аута и неблокирующий ввод/получение, поэтому Queue предоставляет функции join_thread, cancel_join_thread и close для управления поведением фидера. процесс завершается, автоматически не присоединяясь к потоку фидера, использование cancel_join_thread может привести к потере данных из-за того, что фидер не записывает некоторые данные в канал.

В отличие от threading.Queue, multiprocessing.Queue по умолчанию не поддерживает операции join() и task_done, которые требуют использования объектов mp.JoinableQueue.

SimpleQueue — это упрощенная очередь, которая убирает буфер в Queue и устраняет возможные проблемы использования Queue, но методы put и get блокируются и нет контроля тайм-аута.

Суммировать

При сравнении можно обнаружить, что все четыре вышеуказанные структуры реализуют очереди, но их использование различно. Collections.deque реализует очереди на уровне структуры данных, но не поддерживает сценарии приложений. Его можно рассматривать как базовые данные. структура. . Модуль queue реализует очередь для потоков с несколькими продуктами и потоков с несколькими потоками, модуль asyncio.queue реализует очередь для сопрограмм с несколькими продуктами и сопрограммами с несколькими потреблениями, а модуль multiprocessing.queue реализует процессы с несколькими продуктами и потоками с несколькими процессами. очереди потребления Очередь обработки.

Ссылаться на

docs.Python.org/3/library/… из…

docs.Python.org/3/library/… пожалуйста…

docs.Python.org/3/library/… ах…

docs.Python.org/3/library/… нет…

bugs.python.org/issue15329

blog.ft Officer.com/2009/12/Пак Ючон…

Сайрус в.GitHub.IO/2016/04/27/…

Добро пожаловать в мой публичный аккаунт [частная кухня Python]