【问题标题】:Check if element is already in a Queue [duplicate]检查元素是否已经在队列中[重复]
【发布时间】:2013-05-06 13:33:16
【问题描述】:

我在 python 中使用Queue 库,我想保持队列条目的唯一性。

因此,我想在添加到队列之前检查“某物”是否已经在队列中,本质上是这样的函数,适用于队列库:

queue = Queue.Queue()
def in_queue(u):
  return u in queue

或者,我应该使用不同的库/方法来实现这一点吗?

【问题讨论】:

  • 我不确定这是否是一个重复。这种情况下的问题有点复杂,因为他试图将待处理的值 和 已处理的值一起跟踪。然而,在继续回答更复杂的问题之前,那里接受的答案意外地回答了这个问题。

标签: python queue


【解决方案1】:

标准的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 是一种更好的方法。

【讨论】:

  • 像这样扩展队列(例如 OrderedSetQueue)是否仍然是线程安全的?如果您在内部覆盖使用集合的方法,是否会绕过内置同步?
  • 如果你想要一个 FIFO 队列,请使用 self.queue.pop(last=False):orderedset.readthedocs.io
  • @Keith 是的,它仍然是线程安全的。 Queue 的公共方法做同步;子类实现的钩子方法保证只能在锁下调用。查看答案中链接的来源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 1970-01-01
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多