Очередь.Очередь против коллекций.двусторонняя очередь
Мне нужна очередь, в которую несколько потоков могут помещать материал, и несколько потоков могут читать.
Python имеет по крайней мере два класса очереди, очереди.Очередь и коллекции.дек, причем первый, по-видимому, использует последний внутренне. Оба утверждают, что потокобезопасны в документации.
однако в документах очереди также указано:
коллекций.дека является альтернативой
реализация неограниченных очередей
с быстрым атомарным добавлением () и
popleft() операции, которые не
требуется блокировка.
что я думаю, я не совсем понимаю: означает ли это, что deque не полностью потокобезопасен в конце концов?
Если это так, я не могу полностью понять разницу между двумя классами. Я вижу, что очередь добавляет функциональность блокировки. С другой стороны, он теряет некоторые функции deque, такие как поддержка in-operator.
доступ к объекту внутреннего очереди напрямую, составляет
x in Очередь.)(дек
потокобезопасным?
кроме того, почему Queue использует мьютекс для своих операций, когда deque уже является потокобезопасным?
7 ответов:
Queue.Queueиcollections.dequeслужат для разных целей. Очередь.Очередь предназначена для того, чтобы позволить различным потокам взаимодействовать с использованием сообщений/данных в очереди, тогда какcollections.dequeпросто предназначен в качестве структуры данных. Вот почемуQueue.Queueимеет такие методы, какput_nowait(),get_nowait()иjoin(), аcollections.dequeнет.Queue.Queueне предназначен для использования в качестве коллекции, поэтому ему не хватает подобныхinоператора.это сводится к следующему: если у вас есть несколько потоков, и вы хотите, чтобы они могли общаться без необходимости блокировки, вы ищете
Queue.Queue; Если вам просто нужна очередь или двойная очередь в качестве структуры данных, используйтеcollections.deque.наконец, доступ и управление внутренним Деком a
Queue.Queueиграет с огнем - вы действительно не хотите этого делать.
если все, что вы ищете-это потокобезопасный способ передачи объектов между потоками, тогда оба будут работать (как для FIFO, так и для LIFO). Для ФИФО:
Queue.put()иQueue.get()являются потокобезопаснымиdeque.append()иdeque.popleft()являются потокобезопаснымиПримечание:
- прочие операции на
dequeне может быть потокобезопасным, я не уверен.dequeне блок наpop()илиpopleft()таким образом, вы не можете основывать поток потока потребителей на блокировке до тех пор, пока не появится новый элемент.однако, кажется, что deque имеет значительное преимущество эффективности. Вот некоторые результаты тестирования в секундах с помощью CPython 2.7.3 для вставки и удаления 100k элементов
deque 0.0747888759791 Queue 1.60079066852вот тестовый код:
import time import Queue import collections q = collections.deque() t0 = time.clock() for i in xrange(100000): q.append(1) for i in xrange(100000): q.popleft() print 'deque', time.clock() - t0 q = Queue.Queue(200000) t0 = time.clock() for i in xrange(100000): q.put(1) for i in xrange(100000): q.get() print 'Queue', time.clock() - t0
для информации есть авиабилет питона ссылается на потокобезопасность двухсторонней очередью (https://bugs.python.org/issue15329). Название "уточните, какие методы deque являются потокобезопасными"
итог здесь:https://bugs.python.org/issue15329#msg199368
двухсторонняя очередь это функции append(), appendleft(), поп(), popleft () и лен(д) операции являются потокобезопасными в с CPython. Методы добавления имеют DECREF в конце (для случаев, когда maxlen имеет было установлено), но это происходит после всех обновления структуры и инварианты были восстановлены, так что это нормально для лечения этих операций как атомный.
в любом случае, если вы не уверены на 100% и вы предпочитаете надежность и производительность, поставьте лайк замок ;)
dequeявляется потокобезопасным. "операции, которые не требуют блокировки" означает, что вы не должны делать блокировку самостоятельно,dequeзаботится о ней.на
Queueисточник, внутренний дек называетсяself.queueи использует мьютекс для аксессоров и мутаций, так чтоQueue().queueи не нитки-безопасная в использовании.если вы ищете оператор "in", то deque или queue, возможно, не самая подходящая структура данных для вашего проблема.
deque 0.469802 Queue 0.667279@Джонатан немного модифицирует свой код, и я получаю тест с помощью cPython 3.6.2 и добавляю условие в цикл deque для имитации очереди поведения.
import time from queue import Queue import threading import collections mutex = threading.Lock() condition = threading.Condition(mutex) q = collections.deque() t0 = time.clock() for i in range(100000): with condition: q.append(1) condition.notify_all() for _ in range(100000): with condition: q.popleft() condition.notify_all() print('deque', time.clock() - t0) q = Queue(200000) t0 = time.clock() for _ in range(100000): q.put(1) for _ in range(100000): q.get() print('Queue', time.clock() - t0)и кажется, что производительность ограничена эта функция
condition.notify_all()сборники.deque-это альтернативная реализация неограниченных очередей с быстрыми атомарными операциями append() и popleft (), которые не требуют блокировки. очереди документы
(Кажется, у меня нет репутации, чтобы комментировать...) Вы должны быть осторожны, какие методы дека вы используете из разных потоков.
дека.get () кажется потокобезопасным, но я обнаружил, что делаю
for item in a_deque: process(item)может произойти сбой, если другой поток добавляет элементы одновременно. Я получил RuntimeException, который жаловался "deque мутировал во время итерации".
Регистрация collectionsmodule.c чтобы увидеть, какие операции зависят от этого
все одноэлементные методы на
dequeявляются атомарными и потокобезопасными. Все остальные методы также потокобезопасны. Такие вещи, какlen(dq),dq[4]дают мгновенные правильные значения. Но подумайте, например, оdq.extend(mylist): вы не получаете гарантию того, что все элементыmylistхранятся в строке, когда другие потоки также добавляют элементы на той же стороне - но это обычно не является требованием в межпотоковой связи и для поставленной задачи.так
dequeэто ~20x быстрее, чемQueue(который используетdequeпод капотом) и если вам не нужен" удобный " API синхронизации (блокировка / тайм-аут), строгийmaxsizeподчинение или "переопределить эти методы (_put, запросе, ..) реализовать другие организации очереди" поведение подкласса, или когда вы сами заботитесь о таких вещах, то голыйdequeхорошее и эффективное дело для высокоскоростного сообщения Интер-потока.на самом деле интенсивное использование дополнительного мьютекса и дополнительный метод
._get()etc. метод вызывает вQueue.pyэто связано с ограничениями обратной совместимости, прошлым чрезмерным дизайном и отсутствием заботы о предоставлении эффективного решения этой важной проблемы узкого места скорости в межпотоковой связи. Список использовался в более старых версиях Python-но даже список.добавлять./)(поп(0) был и атомной и ориентированы на многопотоковое исполнение ...
Comments