-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
asyncio.gather should not use special Future #77594
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
Comments
asyncio.gather() returns a _GatheringFuture, which inherits from asyncio.Future. This is weird in current asyncio, as futures are supposed to be created with loop.create_future(). So I tried to reimplement gather() without this weird special future. I succeeded, yet I stumbled over weird inconsistencies with cancellation. There are three cases:
the current task raises a CancelledError, but task.cancelled() is false. I consider the last exception actually a bug, but it allows me to make my inheritance-free gather() look to the outside exactly like it used to be. |
I would like to comment on the last observation about current_task().cancel(). I also ran into this corner case recently. When a task is cancelled from outside, by virtue of there being something outside doing the cancelling, the task being cancelled is not currently running, and that usually means the task is waiting at an When one cancels a task from the inside by calling cancel() on the task object, the task will still run as normal until it reaches the next Traceback (most recent call last):
File "cancel_self.py", line 89, in run_one
loop.run_until_complete(coro)
File "C:\Program Files\Python36\lib\asyncio\base_events.py", line 467, in run_until_complete
return future.result()
concurrent.futures._base.CancelledError This is the case described in the original comment. I would also consider this a bug or at least undesired behavior. Since CancelledError is never raised inside the task, code in the coroutine cannot catch it, and after the task returns the return value is lost. For a coroutine that acquires and returns some resource (say asyncio.open_connection()), this means that neither the task itself nor the code awaiting the task can release the resource, leading to leakage. I guess one should be careful not to cancel the current task from the inside. |
I looked a bit into the details, and found that bpo-30048 created the described weird behavior. There they fixed the problem that a cancel is ignored if a coroutine manages to cancel its own task and return immediately. As shown in the discussion there, this is actually something happening in real code, and is a valid use case. They fixed that by setting a CancelledError as an exception raised by the task, but did not cancel that task (they could have, I tested it, it would pass all tests). But this is just a side show of the fact that we have now four different beasts that can be awaited, and behave differently: coroutines, Futures, Tasks, and _GatheringFutures. I think we should consolidate that. |
I really don't want to touch gather code at this point, it's a outdated API in favor of newer |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: