New submission from Mathias Fröjdman:

queue.Queue should have a close() method. The result of calling the method 
would be to raise a new exception - queue.Closed, for any subsequent calls to 
Queue.put, and after the queue is empty, also for Queue.get.

Why: To allow producers (callers of Queue.put) to signal there will be no more 
items, and consumers may stop asking for more by calling Queue.get. Currently 
the opposite (ie. waiting until all produced items/"tasks" have been consumed 
and handled) is possible with Queue.task_done() and Queue.join(). 

This functionality is useful in both application and library code. For example 
in AMQP, a server may push new messages over a TCP connection to a consumer, 
which translates into the library calling Queue.put for received messages, and 
the application using the library calling Queue.get to receive any new 
messages. The consumer may however be cancelled at any time, or the TCP 
connection closed and the Queue.get caller signaled that there will be no more 
messages. With Queue.close() that is easy - without it one needs to wrap the 
Queue.get calls).

In an application context where a KeyboardInterrupt should lead to closing the 
application cleanly, being able to call Queue.close(), catching the Closed 
exception in any consumers (some of which may be in other threads) and exiting 
cleanly makes the job that much easier.

A common pattern in working around this issue is to call Queue.put(None), and 
treat a None from Queue.get() as a signal to clean up. This works well when one 
knows there is at most one consumer. In the case of many consumers, one needs 
to wrap the Queue and for example add another None to the queue in consumers to 
not leave any remaining get() call waiting indefinitely. This pattern occurs 
even in the standard library: 
https://github.com/python/cpython/blob/7b90e3674be86479c51faf872d0b9367c9fc2f96/Lib/concurrent/futures/thread.py#L141

If accepting this proposal, a corresponding change should be made to 
asyncio.Queue.

I have a tentative implementation (no tests or doc outside the module) in 
https://github.com/mwfrojdman/cpython/blob/closeable_queue/Lib/queue.py

The Queue.close() method has an optional argument clear (default False), which 
clears the queue of items if set to true. This is useful for example when 
exiting an application, and one doesn't want consumers to get any more items 
before being raised a Closed exception. The changes are backwards compatible 
for users of the class, ie. if Queue.close() is not called, the behavior stays 
intact. Because of the clear argument, there is a new private method 
Queue._clear(), which does the actual clearing of the queue representation. 
Subclasses for which self.queue.clear() doesn't cut it, need to override it 
before .close(True) works.

Background: https://github.com/python/asyncio/pull/415#issuecomment-263658986

----------
components: Library (Lib)
messages: 288828
nosy: mwf
priority: normal
severity: normal
status: open
title: Add close method to queue.Queue
type: enhancement
versions: Python 3.7

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue29701>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to