Python 通信队列结束
我正在学习使用队列模块,对于如何让队列使用者线程知道队列已完成,我有点困惑。理想情况下,我希望在使用者线程中使用Python 通信队列结束,python,multithreading,queue,Python,Multithreading,Queue,我正在学习使用队列模块,对于如何让队列使用者线程知道队列已完成,我有点困惑。理想情况下,我希望在使用者线程中使用get(),并在队列标记为“完成”时让它抛出异常。有没有更好的方法来传达这一点,而不是附加一个哨兵值来标记队列中的最后一个项目?队列本身并不具有完成或完成的想法。它们可以无限期地使用。要在完成后关闭它,您确实需要在末尾添加None或其他神奇值,并编写逻辑来检查它,如您所述。理想的方法可能是对队列对象进行子类化 请参阅以了解有关队列的更多信息。哨兵是关闭队列的自然方式,但有几件事需要注意
get()
,并在队列标记为“完成”时让它抛出异常。有没有更好的方法来传达这一点,而不是附加一个哨兵值来标记队列中的最后一个项目?队列本身并不具有完成或完成的想法。它们可以无限期地使用。要在完成后关闭它,您确实需要在末尾添加None或其他神奇值,并编写逻辑来检查它,如您所述。理想的方法可能是对队列对象进行子类化
请参阅以了解有关队列的更多信息。哨兵是关闭队列的自然方式,但有几件事需要注意 首先,请记住,您可能有多个消费者,因此您需要为每个正在运行的消费者发送一次sentinel,并确保每个消费者只使用一个sentinel,以确保每个消费者都收到其关机sentinel 其次,请记住队列定义了一个接口,并且在可能的情况下,代码的行为应该与底层队列无关。您可能有一个PriorityQueue,或者您可能有另一个类公开同一接口并以其他顺序返回值 不幸的是,很难同时处理这两个问题。要处理不同队列的一般情况,正在关闭的使用者必须在收到其关闭哨兵后继续使用值,直到队列为空。这意味着它可能会消耗另一个线程的哨兵。这是Queue接口的一个弱点:它应该有一个
Queue.shutdown
调用,以导致所有使用者都抛出异常,但缺少该调用
因此,在实践中:
- 如果您确定只使用常规队列,只需为每个线程发送一个哨兵
- 如果您可能正在使用PriorityQueue,请确保sentinel具有最低优先级
因此,您的说法是队列本身知道它是基于某些标准“完成”的,并且需要通知客户端这一事实。我认为您是正确的,最好的方法是在客户端调用get()且队列处于完成状态时抛出。如果您抛出此选项,则不需要在客户端使用sentinel值。在内部,队列可以检测到它以任何方式“完成”,例如,队列为空,其状态设置为“完成”,等等。我认为不需要哨兵值。队列是FIFO(先进先出)寄存器,因此请记住,消费者可以比生产者更快。当使用者线程检测到队列为空时,通常会执行以下操作之一:
Queue.Queue
的后代,它实现了close
方法。它以原语(未打包)的形式提供。我会把这个整理一下,等我有时间的时候再把它打包好。目前,模块仅包含CloseableQueue
类和Closed
异常类。我计划将其扩展到包括Queue.LifoQueue
和Queue.PriorityQueue
的子类
它目前处于一个相当初步的状态,也就是说,尽管它通过了测试套件,但实际上我还没有在任何方面使用它。您的里程可能会有所不同。我会用激动人心的消息更新这个答案
CloseableQueue
类与Glenn的建议有一点不同,关闭队列将阻止未来的put
s,但在队列清空之前不会阻止未来的get
s。这对我来说是最有意义的;似乎清除队列的功能可以作为一个单独的mixin*添加,该mixin*与closeability功能正交。因此,基本上对于CloseableQueue
,关闭队列表示最后一个元素已被put
。还有一个选项可以通过将last=True
传递到最终的put
调用来实现原子化。队列清空后,对put
的后续调用、对get
的后续调用以及与这些描述匹配的未完成阻止调用将引发Closed
异常
这在单个生产者为一个或多个消费者生成数据的情况下非常有用,但在消费者等待特定项目或项目集的多重安排中也非常有用。特别是,它没有提供一种方法来确定所有的生产商都已经完成了生产。要实现这一目标,需要提供某种方式来注册制作人(.open()
?),以及一种方式来表明制作人注册本身已经结束
建议和/或代码审查是非常受欢迎的。我还没有写过很多并发代码,但希望测试套件足够全面,代码通过测试的事实是一个标志
$ easy_install CloseableQueue