我正在学习使用“队列”模块,并且对如何使队列使用者线程知道队列已完成感到有些困惑。理想情况下,我想在使用者线程中使用get()
,如果队列已标记为“完成”,它会抛出异常。有没有比通过附加哨兵值标记队列中的最后一项更好的通信方式了?
最佳答案
原始(大多数已更改;请参见下面的更新)
基于suggestions的一些Glenn Maynard(谢谢!)和其他,我决定汇总实现Queue.Queue
方法的close
的后代。它以原始(未包装)module的形式提供。我会再清理一点,并在我有更多时间时将其正确包装。目前,该模块仅包含CloseableQueue
类和Closed
异常类。我打算将其扩展为也包括Queue.LifoQueue
和Queue.PriorityQueue
的子类。
目前,它处于一个相当初步的状态,也就是说,尽管它通过了测试套件,但实际上我还没有使用它。你的旅费可能会改变。我将通过令人振奋的消息来更新此答案。CloseableQueue
类与Glenn的建议有所不同,因为关闭队列将阻止将来的put
,但不会阻止将来的get
,直到清空队列。这对我来说最有意义。清除队列的功能似乎可以作为单独的mixin *添加,而该mixin *与可关闭性功能正交。因此,基本上使用CloseableQueue
,通过关闭队列,您可以指示最后一个元素是put
。还可以通过将last=True
传递给最终的put
调用来自动执行此操作。队列被清空后,对put
的后续调用以及对get
的后续调用,以及与这些描述匹配的未完成阻塞调用,将引发Closed
异常。
这在单个生产者正在为一个或多个消费者生成数据的情况下最有用,但对于消费者正在等待特定项目或一组项目的多重布局也很有用。特别是,它没有提供确定所有生产者都已完成生产的方法。要使该工作正常进行,就需要提供某种注册生产者的方式(.open()
?),以及一种指示生产者注册本身已关闭的方式。
建议和/或代码审查非常欢迎。我还没有编写很多并发代码,但是希望测试套件足够彻底,以确保代码通过它的事实表明了代码的质量,而不是套件的缺乏。我能够重用Queue模块测试套件中的一堆代码:文件本身包含在此模块中,并用作各种子类和例程(包括回归测试)的基础。这可能(希望)有助于避免测试部门完全无能为力。代码本身仅用相当小的更改就覆盖了Queue.get
和Queue.put
,并添加了close
和closed
方法。
我有意避免在代码本身和测试套件中使用任何新奇的幻想,例如上下文管理器,以保持代码与Queue模块本身一样向后兼容,这实际上是相当向后的。我可能会在某个时候添加__enter__
和__exit__
方法;否则,contextlib的closing函数应适用于CloseableQueue实例。
*:在这里我宽松地使用术语“mixin”。由于Queue
模块的类是老式的,因此需要使用类工厂函数来混合mixins。有一些限制;在Guido禁止的地方提供空白。
更新
CloseableQueue模块现在提供CloseableLifoQueue
和CloseablePriorityQueue
类。我还添加了一些便利功能来支持迭代。仍然需要将其作为适当的软件包进行返工。有一个类工厂函数,可以方便地对其他Queue.Queue
派生的类进行子类化。
更新2CloseableQueue
现在可以通过PyPI获得,例如和
$ easy_install CloseableQueue
欢迎发表评论和批评,特别是来自此答案的匿名评论家。