You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Finalization of non-exhausted asynchronous generators is deferred #88684
There is a strong link somewhere which prevents finalization of the asynchronous generator object until leaving the outer function.
Tested on CPython 3.7-3.11. In PyPy "finalize inner" is not printed at all. Using closing() and aclosing() is the right way to get deterministic finalization, but in any case it would be better to get rid of strong link which prevents finalization of the asynchronous generator object.
Sorry, I do not understand what do you mean. The problem is that non-exhausted asynchronous generators are not finalized until asyncio.run() is finished. This differs from synchronous generators which are finalized as early as possible (in CPython).
I am wondering whether the issue is in asyncio.run, or in the basic async generator implementation. If the latter, you should be able to demonstrate this with a manual "driver" (trampoline?) instead of asyncio.run.
That's a rather literalist interpretation of my question. :-) I meant whether you can come up with a repro without an event loop framework, since that would presumably make reasoning about the root cause of the problem easier.
The behaviour cannot be changed without significant changes to the interpreter. The documentation will be handled for this as part of #100108 so closing.
Activity
serhiy-storchaka commentedon Jun 27, 2021
In the following example:
the output in CPython is:
finalize inner
finalize outer
END
But in similar example for asynchronous generator:
the output in CPython is:
finalize outer
finalize inner
END
There is a strong link somewhere which prevents finalization of the asynchronous generator object until leaving the outer function.
Tested on CPython 3.7-3.11. In PyPy "finalize inner" is not printed at all. Using closing() and aclosing() is the right way to get deterministic finalization, but in any case it would be better to get rid of strong link which prevents finalization of the asynchronous generator object.
gvanrossum commentedon Jun 28, 2021
Can you repro this without asyncio?
serhiy-storchaka commentedon Jun 28, 2021
Sorry, I do not understand what do you mean. The problem is that non-exhausted asynchronous generators are not finalized until asyncio.run() is finished. This differs from synchronous generators which are finalized as early as possible (in CPython).
gvanrossum commentedon Jun 28, 2021
I am wondering whether the issue is in asyncio.run, or in the basic async generator implementation. If the latter, you should be able to demonstrate this with a manual "driver" (trampoline?) instead of asyncio.run.
serhiy-storchaka commentedon Jun 28, 2021
Inlined asyncio.run(func()) is roughly equivalent to the following code:
If comment out loop.run_until_complete(loop.shutdown_asyncgens()) I get the following output:
finalize outer
Task was destroyed but it is pending!
task: <Task pending name='Task-2' coro=<<async_generator_athrow without __name__>()>>
END
No "finalize inner" but a warning about pending task instead.
On other hand, the following code
produces the output in expected order:
finalize inner
finalize outer
END
10 remaining items
gvanrossum commentedon Jul 19, 2022
That's a rather literalist interpretation of my question. :-) I meant whether you can come up with a repro without an event loop framework, since that would presumably make reasoning about the root cause of the problem easier.
graingert commentedon Jul 19, 2022
trio documents a one-tick finalization window here: https://github.com/python-trio/trio/blob/35319b3d4b881032416bfd733e0ac5239ce4c46d/trio/_core/_asyncgens.py#L26-L30 and here https://trio.readthedocs.io/en/stable/reference-core.html#finalization
gvanrossum commentedon Jul 19, 2022
Ah, sorry. The whole point of the bug seems to be that the event loop hangs on to an extra reference, and there is a reason.
I should really recuse myself from this issue since I don't understand async generators.
graingert commentedon Jul 19, 2022
This looks like it could be an asyncio bug - asyncio should use the firstiter hook to keep a reference to generators that need shutting down
graingert commentedon Jul 19, 2022
seems that got fixed:
prints:
kumaraditya303 commentedon Apr 16, 2023
The behaviour cannot be changed without significant changes to the interpreter. The documentation will be handled for this as part of #100108 so closing.
kumaraditya303 commentedon Apr 16, 2023
For anyone who comes here for a possible fix which always works: