我需要一个队列,多个线程可以放入东西,多个线程可以读取.
Python至少有两个队列类,Queue.Queue和collections.deque,前者似乎在内部使用后者.两者都声称在文档中是线程安全的.
但是,队列文档还指出:
collections.deque是无界队列的替代实现,具有快速原子append()和popleft()操作,不需要锁定.
我想我不太沉思:这是否意味着deque毕竟不是完全线程安全的?
如果是,我可能不完全理解这两个类之间的区别.我可以看到Queue添加了阻止功能.另一方面,它失去了一些deque功能,如支持运营商.
直接访问内部deque对象是
x在队列().deque
线程安全的?
另外,为什么当deque已经是线程安全的时候,Queue会使用互斥锁进行操作?
Queue.Queue
并collections.deque
服务于不同的目的.Queue.Queue旨在允许不同的线程使用排队的消息/数据进行通信,而collections.deque
只是用作数据结构.这就是为什么Queue.Queue
有类似的方法put_nowait()
,get_nowait()
和join()
,而collections.deque
不会.Queue.Queue
不打算用作集合,这就是为什么它缺乏in
运营商的喜欢.
它归结为:如果你有多个线程,并且你希望它们能够在不需要锁的情况下进行通信,那么你正在寻找Queue.Queue
; 如果您只想将队列或双端队列作为数据结构,请使用collections.deque
.
最后,访问和操纵a的内部双端队员Queue.Queue
正在玩火 - 你真的不想这样做.
如果您正在寻找的是一种在线程之间传输对象的线程安全方法,那么两者都可以工作(FIFO和LIFO都有).对于FIFO:
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
有关信息,请参阅deque thread-safety引用的Python票证(https://bugs.python.org/issue15329).标题"澄清哪种deque方法是线程安全的"
这里的底线:https://bugs.python.org/issue15329#msg199368
deque的append(),appendleft(),pop(),popleft()和len(d)操作在CPython中是线程安全的.append方法最后有一个DECREF(对于设置了maxlen的情况),但是在完成所有结构更新并且不变量已经恢复之后会发生这种情况,因此可以将这些操作视为原子操作.
无论如何,如果你不是100%确定并且你更喜欢可靠性而不是性能,那么就像锁一样;)