Queue.Queue与collections.deque

我需要一个multithreading可以放入东西的队列,多个线程可以读取。

Python至less有两个队列类,Queue.Queue和collections.deque,前者似乎在内部使用后者。 两者都声称在文档中是线程安全的。

但是,队列文档还指出:

collections.deque是一个无界队列的替代实现,具有快速primefacesappend()和popleft()操作,不需要locking。

我想我并不是无意的:这是否意味着deque并不完全是线程安全的?

如果是这样,我可能不完全了解这两个阶级之间的区别。 我可以看到Queue添加了阻止function。 另一方面,它失去了一些像支持in-operator这样的dequefunction。

是直接访问内部deque对象

x在Queue()。deque

线程安全的?

另外,为什么当队列已经是线程安全的时候,Queue为它的操作使用一个互斥锁呢?

Queue.Queuecollections.deque有不同的用途。 Queue.Queue旨在允许不同的线程使用排队的消息/数据进行通信,而collections.deque只是用作数据结构。 这就是为什么Queue.Queue有像put_nowait()get_nowait()join() ,而collections.deque则不是。 Queue.Queue并不打算用作集合,这就是为什么它缺lessin运算符之类的东西。

归结起来,如果你有多个线程,并且你希望它们能够在不需要锁的情况下进行通信,那么你正在寻找Queue.Queue ; 如果您只想将队列或双端队列作为数据结构,请使用collections.deque

最后,访问和操作Queue.Queue的内部双端队列正在玩火 – 你真的不想这样做。

如果你正在寻找的是在线程之间传递对象的线程安全的方式 ,那么两者都可以工作(FIFO和LIFO)。 对于FIFO:

  • Queue.put()Queue.get()是线程安全的
  • deque.append()deque.popleft()是线程安全的

注意:

  • deque其他操作可能不是线程安全的,我不确定。
  • deque不会在pop()popleft()上阻塞,因此您不能将消费者线程stream阻塞到新项目到达之前。

但是,似乎deque有一个显着的效率优势 。 以下是使用CPython 2.7.3秒插入和删除100k项目的一些基准testing结果

 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 

deque是线程安全的。 “不需要locking的操作”意味着你不必自己locking, deque可以处理它。

看看Queue源,内部deque被称为self.queue并且使用一个互斥体来访问器和突变,所以Queue().queue 不是线程安全的。

如果你正在寻找一个“in”运算符,那么deque或queue可能不是你问题的最合适的数据结构。

有关信息,有一个引用deque线程安全的Python票( https://bugs.python.org/issue15329 )。 标题“澄清哪些deque方法是线程安全的”

底线在这里: https : //bugs.python.org/issue15329#msg199368

在CPython中,deque的append(),appendleft(),pop(),popleft()和len(d)操作是线程安全的。 append方法在最后有一个DECREF(对于已经设置了maxlen的情况),但是在所有结构更新完成并且不variables已经被恢复之后,会发生这种情况,所以将这些操作视为primefaces是可以的。

无论如何,如果你不是100%肯定,你更喜欢可靠性而不是性能,只需要像Lock一样;)

(看来我没有评论的声望…)你需要小心你使用不同的线程使用哪个方法。

deque.get()似乎是线程安全的,但我发现这样做

 for item in a_deque: process(item) 

如果另一个线程同时添加项目可能会失败。 我得到了一个RuntimeException,抱怨“迭代过程中发生变异”。

检查collectionsmodule.c以查看哪些操作受此影响

deque上的所有单元素方法都是primefaces的和线程安全的。 所有其他的方法也是线程安全的。 像len(dq)dq[4]产生瞬时的正确值。 但是,想想例如关于dq.extend(mylist) :当其他线程也在同一个dq.extend(mylist)追加元素时,你不能保证mylist中的所有元素都被连续存档 – 但是这通常不是线程间通信的要求和被质疑的任务。

因此,一个dequeQueue (使用deque底层)快20倍,除非你不需要“舒适的”同步API(blocking / timeout),严格的maxsize obeyance或者“Override these methods(_put, _get,..)来实现其他队列组织的子分类行为,或者当你自己处理这些事情的时候,那么对于高速的线程间通信来说,一个纯粹的deque是一个很好的和高效的处理。

事实上,在._get()额外的互斥量和额外的方法._get()等方法调用的Queue.py是由于向后兼容性约束,过去的devise和缺乏关心为这个重要的速度瓶颈问题提供有效的解决scheme在线程间通信。 一个列表用于旧的Python版本 – 但是,即使list.append()/。pop(0)是&primefaces和线程安全…