New submission from Hrvoje Nikšić <hnik...@gmail.com>:

Judging by questions on the StackOverflow python-asyncio tag[1][2], it seems 
that users find it hard to understand how to use as_completed correctly. I have 
identified three issues:

* It's somewhat sparingly documented.

A StackOverflow user ([2]) didn't find it obvious that it runs the futures in 
parallel. Unless one is already aware of the meaning, the term "as completed" 
could suggest that they are executed and completed sequentially.

* Unlike its concurrent.futures counter-part, it's non-blocking.

This sounds like a good idea because it's usable from synchronous code, but it 
means that the futures it yields aren't completed, you have to await them 
first. This is confusing for a function with "completed" in the name, and is 
not the case with concurrent.futures.as_completed, nor with other waiting 
functions in asyncio (gather, wait, wait_for).

* It yields futures other than those that were passed in.

This prevents some usual patterns from working, e.g. associating the results 
with context data, such as Python docs itself uses for 
concurrent.futures.as_completed in 
https://docs.python.org/3/library/concurrent.futures.html#threadpoolexecutor-example
 .  See SO question [1] for a similar request in asyncio.


Here is my proposal to address the issues.

I believe the usage problems stem from as_completed predating the concept of 
async iterators. If we had async iterators back then, as_completed would have 
been an obvious candidate to be one. In that case it could be both "blocking" 
(but not for the event loop) and return the original futures. For example:

async def as_completed2(fs):
    pending = set(map(asyncio.ensure_future(fs)))
    while pending:
        done, pending = await asyncio.wait(pending, 
return_when=asyncio.FIRST_COMPLETED)
        yield from done

(It is straightforward to add support for a timeout argument.)

I propose to deprecate asyncio.as_completed and advertise the async-iterator 
version like the one presented here - under a nicer name, such as as_done(), or 
as_completed_async().



[1] 
https://stackoverflow.com/questions/50028465/python-get-reference-to-original-task-after-ordering-tasks-by-completion
[2] 
https://stackoverflow.com/questions/50355944/yield-from-async-generator-in-python-asyncio

----------
components: asyncio
messages: 316773
nosy: asvetlov, hniksic, yselivanov
priority: normal
severity: normal
status: open
title: Provide an async-generator version of as_completed
versions: Python 3.8

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

Reply via email to