标准的Queue 类不能被迭代或以其他方式检查。
但是,它是为扩展而构建的。
首先,如果您查看source(从文档链接),您可以覆盖这些钩子方法_init、_qsize、_put 和_get 以更改实现。看看主类下面的子类,就知道它们是怎么做的了。
因此,一件简单的事情就是用set 替换deque 实现:
class SetQueue(Queue.Queue):
def _init(self, maxsize):
self.queue = set()
def _put(self, item):
self.queue.add(item)
def _get(self):
return self.queue.pop()
(我没有实现_qsize,因为默认的return len(self.queue)很好。)
现在你不必检查,只需将它添加到队列中,如果它已经存在,它将被忽略。
当然,这有一个缺点是队列不再有序。但是你可以通过使用OrderedSet 来解决这个问题(类似于collections 中的OrderedDict)。有一个 recipe 链接自 collections 文档。一旦你有了:
class OrderedSetQueue(Queue.Queue):
def _init(self, maxsize):
self.queue = OrderedSet()
def _put(self, item):
self.queue.add(item)
def _get(self):
return self.queue.pop()
如果您真的希望能够检查队列中的值,您可以为此添加一个方法:
class CheckableQueue(Queue.Queue): # or OrderedSetQueue
def __contains__(self, item):
with self.mutex:
return item in self.queue
但是,这会在您的代码中引入竞争条件。例如,如果你这样做:
if x not in my_queue:
my_queue.put(x)
总是有可能x 在您检查时不在队列中,但在您调用put 时在队列中。事实上,不会不安全的这个函数的唯一用途是某种乐观检查(如果值不在队列中现在,做一些昂贵的工作,然后尝试添加它,如果在此期间添加了值,则接受这项工作是浪费的)——与 Queue.full() 存在的原因相同。
确保安全的唯一方法是将两个操作放在一起锁定:
with my_queue.mutex:
if x not in my_queue:
my_queue.put(x)
但是在这一点上,您首先违背了使用Queue 的目的。 (您还依赖于 Queue.mutex 是一个可递归输入的互斥锁这一事实。)最好将该操作添加为您的 Queue 子类的方法。
如果您总是想先检查并仅在不存在时添加,OrderedSetQueue 是一种更好的方法。