获取Python队列的索引访问的最佳方法,线程安全

11

我有一个队列(来自Queue模块),我想要对它进行索引访问(例如,在不从队列中删除该项的情况下请求第4个项目)。

我看到队列内部使用了deque,并且deque有索引访问,但问题是如何在不(1)搞乱队列或(2)破坏线程安全性的情况下使用deque。


1
你为什么使用队列而不是按顺序入队和出队?这只是线程之间共享的对象吗? - S.Lott
1
队列中有按顺序排列的入列和出列元素。 "按顺序"的意思是,它们很少被访问,除了在末尾添加和从另一端弹出之外。 为什么要打破“排队”的默认假设呢? - S.Lott
1
@S.Lott,在 Queue.Queue 中的队列调度策略是设计为可通过子类化进行自定义的 - 这就是 self.mutexself.queue 等具有公共名称的原因:恰好是为了指示它们允许高级应用程序(仔细地; - )自定义行为(如果 Queue 只是一个黑盒,它会为其内部使用不同的命名方案)。 - Alex Martelli
@S.Lott:我主要将队列用作队列(即FIFO),但在某些情况下,我想像列表一样访问它。您认为我应该做些其他的事情吗? - Ram Rachum
@cool-RR:如果大部分是FIFO,那么队列是很好的选择。问题(以及您的评论)非常令人困惑。非顺序(即非FIFO)队列不是一个合适的队列。但是,如果它大多数情况下是按顺序访问的(即FIFO),那么它就是一个合适的队列(也许具有带外或前瞻功能)。 - S.Lott
显示剩余2条评论
1个回答

14
import Queue

class IndexableQueue(Queue):
  def __getitem__(self, index):
    with self.mutex:
      return self.queue[index]

当然,在索引成功或引发IndexError时释放互斥锁非常关键,我正在使用with语句来实现这一点。在旧版Python中,会使用try/finally语句来达到相同的效果。


1
太干净了...我现在正在用Java处理线程,但并不好玩。 - Bite code
很棒的答案。不幸的是,没有任何文档说明队列适合(甚至是意味着,正如你所说)用子类访问其内部成员。它们被“公开”是唯一的线索。即使在Queue.py模块的源代码中也没有明确说明,这很遗憾。我认为,你在这个答案中的代码片段应该成为标准库文档中Queue的一个例子。 - Eli Bendersky
@eliben,你说得对,Queue.py的内部文档(一直以来)都非常低效,但至少现在有所改善...例如,在我们记录其可子类化性(第2版Cookbook中的9.3配方)时,文档中也没有提到,现在至少提供了几个有用的子类...;-) - Alex Martelli
@Alex Martelli:我注意到这个mutex是一个Lock,而不是RLock。你认为这样做有好的理由吗?如果它是一个RLock,我可以确保在我访问它的整个会话期间没有人触碰队列。你怎么看? - Ram Rachum
2
@cool-RR,问题在于 Queue 中的锁定比较复杂 —— 它基于互斥锁(mutex)有一些条件。因此,在持有 mutex 的同时调用不同的队列方法非常危险,即使是 RLock 也可能发生死锁!为什么不只是将 self.queue 复制到您自己的本地变量中(同时持有 mutex),然后释放 mutex 并访问您的本地副本呢?(我强烈建议您除了“神圣”的方法以外不要以任何方式改变 self.queue,否则您还需要信号正确的条件等等 —— 噩梦!) - Alex Martelli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接