I’m learning to use the Queue module, and am a bit confused about how a queue consumer thread can be made to know that the queue is complete. Ideally I’d like to use get() from within the consumer thread and have it throw an exception if the queue has been marked “done”. Is there a better way to communicate this than by appending a sentinel value to mark the last item in the queue?
I’m learning to use the Queue module, and am a bit confused about how
Share
original (most of this has changed; see updates below)
Based on some of the suggestions (thanks!) of Glenn Maynard and others, I decided to roll up a descendant of
Queue.Queuethat implements aclosemethod. It’s available in the form of a primitive (unpackaged) module. I’ll clean this up a bit and package it properly when I have a bit more time. For now the module only contains theCloseableQueueclass and theClosedexception class. I’m planning to expand it to also include subclasses ofQueue.LifoQueueandQueue.PriorityQueue.It’s in a pretty preliminary state currently, which is to say that although it passes its test suite, I haven’t actually used it for anything yet. Your mileage may vary. I’ll keep this answer updated with exciting news.
The
CloseableQueueclass differs a bit from Glenn’s suggestion in that closing the queue will prevent futureputs, but not prevent futuregets until the queue is emptied. This made the most sense to me; it seemed like functionality to clear the queue could be added as a separate mixin* that would be orthogonal to the closeability functionality. So basically withCloseableQueue, by closing the queue you indicate that the last element has beenput. There’s also an option to do this atomically by passinglast=Trueto the finalputcall. Subsequent calls toput, and subsequent calls togetonce the queue is emptied, as well as outstanding blocked calls matching those descriptions, will raise theClosedexception.This is mostly useful for situations where a single producer is generating data for one or more consumers, but it could also be useful for a multi-multi arrangement where consumers are waiting for a particular item or set of items. In particular it doesn’t provide a way to determine that all of a number of producers have finished production. Getting that working would entail the provision of some way to register producers (
.open()?), as well as a way to indicate that producer registration is itself closed.Suggestions and/or code reviews are quite welcome. I haven’t written a whole lot of concurrency code, but hopefully the test suite is thorough enough that the fact that the code passes it is an indication of the code’s quality, rather than the suite’s lack thereof. I was able to reuse a bunch of the code from the Queue module’s test suite: the file itself is included in this module and used as a basis for various subclasses and routines, including regression testing. This probably (hopefully) helped to avoid complete ineptitude in the testing department. The code itself just overrides
Queue.getandQueue.putwith fairly minimal changes, and adds thecloseandclosedmethods.I’ve sort of intentionally avoided using any new-fangled fanciness like context managers in both the code itself and in the test suite in an effort to keep the code as backwards-compatible as is the Queue module itself, which is considerably backwards indeed. I’ll probably add
__enter__and__exit__methods at some point; otherwise, the contextlib’s closing function should be applicable to a CloseableQueue instance.*: Here I use the term “mixin” loosely. As the
Queuemodule’s classes are old-style, mixins would need to be mixed using class factory functions; some restrictions apply; offer void where prohibited by Guido.update
The CloseableQueue module now provides
CloseableLifoQueueandCloseablePriorityQueueclasses. I’ve also added some convenience functions to support iteration. Still need to rework it as a proper package. There’s a class factory function to allow for convenient subclassing of otherQueue.Queue-derived classes.update 2
CloseableQueueis now available via PyPI, e.g. withComments and criticism are welcome, especially from this answer’s anonymous downvoter.