我正在学习使用“队列”模块,并且对如何使队列使用者线程知道队列已完成感到有些困惑。理想情况下,我想在使用者线程中使用get(),如果队列已标记为“完成”,它会抛出异常。有没有比通过附加哨兵值标记队列中的最后一项更好的通信方式了?

最佳答案

原始(大多数已更改;请参见下面的更新)

基于suggestions的一些Glenn Maynard(谢谢!)和其他,我决定汇总实现Queue.Queue方法的close的后代。它以原始(未包装)module的形式提供。我会再清理一点,并在我有更多时间时将其正确包装。目前,该模块仅包含CloseableQueue类和Closed异常类。我打算将其扩展为也包括Queue.LifoQueueQueue.PriorityQueue的子类。

目前,它处于一个相当初步的状态,也就是说,尽管它通过了测试套件,但实际上我还没有使用它。你的旅费可能会改变。我将通过令人振奋的消息来更新此答案。
CloseableQueue类与Glenn的建议有所不同,因为关闭队列将阻止将来的put,但不会阻止将来的get,直到清空队列。这对我来说最有意义。清除队列的功能似乎可以作为单独的mixin *添加,而该mixin *与可关闭性功能正交。因此,基本上使用CloseableQueue,通过关闭队列,您可以指示最后一个元素是put。还可以通过将last=True传递给最终的put调用来自动执行此操作。队列被清空后,对put的后续调用以及对get的后续调用,以及与这些描述匹配的未完成阻塞调用,将引发Closed异常。

这在单个生产者正在为一个或多个消费者生成数据的情况下最有用,但对于消费者正在等待特定项目或一组项目的多重布局也很有用。特别是,它没有提供确定所有生产者都已完成生产的方法。要使该工作正常进行,就需要提供某种注册生产者的方式(.open()?),以及一种指示生产者注册本身已关闭的方式。

建议和/或代码审查非常欢迎。我还没有编写很多并发代码,但是希望测试套件足够彻底,以确保代码通过它的事实表明了代码的质量,而不是套件的缺乏。我能够重用Queue模块测试套件中的一堆代码:文件本身包含在此模块中,并用作各种子类和例程(包括回归测试)的基础。这可能(希望)有助于避免测试部门完全无能为力。代码本身仅用相当小的更改就覆盖了Queue.getQueue.put,并添加了closeclosed方法。

我有意避免在代码本身和测试套件中使用任何新奇的幻想,例如上下文管理器,以保持代码与Queue模块本身一样向后兼容,这实际上是相当向后的。我可能会在某个时候添加__enter____exit__方法;否则,contextlib的closing函数应适用于CloseableQueue实例。

*:在这里我宽松地使用术语“mixin”。由于Queue模块的类是老式的,因此需要使用类工厂函数来混合mixins。有一些限制;在Guido禁止的地方提供空白。

更新

CloseableQueue模块现在提供CloseableLifoQueueCloseablePriorityQueue类。我还添加了一些便利功能来支持迭代。仍然需要将其作为适当的软件包进行返工。有一个类工厂函数,可以方便地对其他Queue.Queue派生的类进行子类化。

更新2
CloseableQueue现在可以通过PyPI获得,例如和

$ easy_install CloseableQueue

欢迎发表评论和批评,特别是来自此答案的匿名评论家。

09-17 20:11