-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
Asynchronous generator memory leak #85401
Comments
The resource used by asynchronous generator can't be released properly when works with "asend" method. Besides, in Python 3.7-, a RuntimeError was raised when asyncio.run complete, but the message is puzzling: In Python 3.8+, No Exception showed. Python3.5 unsupport yield in async function, so it seems no affect? |
Only 3.8+ for bug fixes. |
From the given example, if I add "await q.aclose()" after "await q.asend(123456)" it does not leak the memory. This is a good example showing that we should always wrap async generators with explicit "aclosing" context manager (which does not exist yet in the stdlib). We may need to update the documentation to recommend explicit aclosing of async generators. |
I've searched the Python documentation and the docs must be updated to explicitly state the necessity of aclose(). refs) I'm not sure that what the original authors' intention is, but for me, it looks like that calling aclose() is an optional thing and the responsibility to call aclose() on async generators is left to the asyncgen-shutdown handler of the event loop. The example in this issue show that we need to aclose asyncgens whenever we are done with it, even far before shutting down the event loop. |
Huh, this is very weird. I can confirm that the async generator objects aren't cleaned up until loop shutdown on asyncio. On the trio main branch, we don't yet use the However, if I check out this PR that will add it: python-trio/trio#1564 ...then we see the same bug happening with Trio: all the async generators are kept around until loop shutdown. Also, it doesn't seem to be a circular references issue – if I explicitly call This doesn't make any sense, because asyncio/trio only keep weak references to the async generator objects, so they should still be freed. So maybe the |
...On closer examination, it looks like that Trio PR has at least one test that checks that async generators are collected promptly after they stop being referenced, and that test passes: https://github.com/python-trio/trio/pull/1564/files#diff-c79a78487c2f350ba99059813ea0c9f9R38 So, I have no idea what's going on here. |
Oh! I see it. This is actually working as intended. What's happening is that the event loop will clean up async generators when they're garbage collected... but, this requires that the event loop get a chance to run. In the demonstration program, the main task creates lots of async generator objects, but never returns to the main loop. So they're all queued up to be collected, but it can't actually happen until you perform a real async operation. For example, try adding 'await asyncio.sleep(1)` before the input() call so that the event loop has a chance to run, and you'll see that the objects are collected immediately. So this is a bit tricky, but this is actually expected behavior, and falls under the general category of "don't block the event loop, it will break stuff". |
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: