-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-119154: Simplify consumers by adding *.Queue.iter()
and *.Queue.iter_nowait()
#120925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Co-authored-by: Guido van Rossum <guido@python.org>
Co-authored-by: Zac Hatfield-Dodds <zac.hatfield.dodds@gmail.com>
pythongh-120924: Simplify consumers by adding `*.Queue.iter()` and `*.Queue.iter_nowait()`
queue.Queue.iter()
and queue.Queue.iter_nowait()
*.Queue.iter()
and *.Queue.iter_nowait()
Sorry, I didn't intend to request a review. I merged the pull requests to leave it at just 2. |
I’m sorry, I am currently on vacation and dealing with health issues. I will not be a available to review this. |
*.Queue.iter()
and *.Queue.iter_nowait()
*.Queue.iter()
and *.Queue.iter_nowait()
*.Queue.iter()
and *.Queue.iter_nowait()
*.Queue.iter()
and *.Queue.iter_nowait()
…9-35-14.gh-issue-119154.7CXFaX.rst
Note, I (with Erlend Aasland concurring) marked #120503 as rejected 2 weeks ago. Rather than accept the result from the |
I first asked whether this would be a better API: #120503 (comment). And clarified how I'll attempt tot address the previous rejection. |
If you want, we can delay this change until Python 3.15.
Is it clearer with
We haven't done that with
According to my GitHub search, only a minority of 24.5% are "simple" consumers:4
"performance is not the only golden rule for CPython. Code readability is critical for maintenance"5
An error is raised if it's the first element. "This ensures the queue is not empty (without risking race conditions). That seems like the only sensible behaviour as queues aren't infinite (why would you otherwise want to iterate over them without waiting).7 def iter(self, block=True, timeout=None):
try:
yield self.get(block=block, timeout=timeout)
except ShutDown:
return
try:
while True:
yield self.get(block=block, timeout=timeout)
except (Empty, ShutDown):
return
You can do that after the for loop:8 for ... in q.iter():
# do something
cleanup(q)
In that case, create a subclass.8
It's safer to call
I think that in most cases a subclass won't be necessary. Footnotes
|
We discussed this at the sprint today and agreed this (or any variation of it) should not be done. Multiple reasons were given. The most important was that this is only one of the multitude of reasonable ways to use existing queue API: the new shutdown exception, previously existing custom exceptions, waiting for timeouts, multiple producers, multiple consumers, having a second queue for two-way communication, etc. Another reason was that a senior concurrency developer had become averse to trend widening existing APIs to support the various dunder method protocols (iterator, context manager etc). Other devs agreed that a for-loop front-end would hide (make implicit) details that we really want to be explicit for code review (i.e. when blocking happens and what exception will be caught). This senior concurrency dev suggested that I write a small edit to the docs showing a user could easily write a wrapper like this. I'll do that in a separate PR. |
Does this decision apply to #120491 as well? In that case both the issue and PR should be closed. |
Purpose
Currently consuming items from a queue can be a bit more complex than necessary. You need to
q.task_done()
after processing each itemBy adding
*.Queue.iter()
and*.Queue.iter_nowait()
, this becomes a bit easier, you only need to callqueue.shutdown()
.Overview of changes
asyncio
queue.Queue.iter()
returns an asynchronous generator which iterates over the queue of itemsqueue.Queue.iter_nowait()
returns a generator which iterates over the queue of items without blocking._AsyncQueueIterator
has been added to handle the asynchronous iterationqueue.py
queue.Queue.iter()
returns a generator which iterates over the queue of itemsqueue.Queue.iter_nowait()
returns a generator which iterates over the queue of items without blocking.Examples
asyncio
Without iteration
With iteration
Output
queue as final step
Without iteration
With iteration
Output
queue not as final step
Without iteration
With iteration
Output
asyncio.Queue.__aiter__
#119154📚 Documentation preview 📚:
library/queue.html
library/asyncio-queue.html