-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
asyncio.all_tasks() crashes if asyncio is used in multiple threads #80788
Comments
This problem was identified in https://bugs.python.org/issue34970 but I think the fix might have been incorrect. The theory in bpo-34970 was that GC was causing the weakrefset for My thoughts on this problem are:
Repro code:
Output:
|
Thanks for the report! I see 3 ways to fix the bug:
Thus I'm inclining to bullet 2. |
The fix can be applied to 3.7 and 3.8 only, sorry. |
My preference would actually be number 3 because: 1: I agree that this isn't really a safe option because it could slow things down (possibly a lot)
Thats fine, you can work around the issue using asyncio.set_task_factory to something that tracks the tasks per loop with some care. |
Sorry, I've missed that the loop has hashable requirement already. I'm just curious why do you call |
I will give it a try and see what I come up with.
Yeah this was my concern too, the adding and removing from the WeakDict[AbstractEventLoop, WeakSet[Task]] for Another option would be to have the WeakSet[Task] attached to the loop itself then because using the same loop in multiple threads not at all thread safe already that would contain the problem. You mentioned "third-party loops" which may make this option impossible.
In reality we aren't using
|
Note: there's a discussion on GitHub on PR 13971 being a bad solution: #13971 (comment) They should be reverted (or fixed forward) for 3.8 and 3.9. I'm OK with this modifying the AbstractEventLoop API if need be for 3.8. Just have a PR ready in the next two weeks. |
Lukasz, please don't rush. I see the only way to make it perfect: get rid of weak refs entirely. There is such possibility: call asyncio._unregister_task() explicitly when the task is done (finished with success or failure or cancelled). The only requirement is that task should call this _unregister_task() method. At the time of work on 3.7, Yuri and I considered this implementation but rejected it because there was a (very low) chance that somebody may implement own task, register custom task factory and don't call _unregister_task(). I never see a code that implements asyncio task from scratch, people always reuse existing asyncio.Task. So, maybe the idea is not such bad. It can be implemented easily. I'm volunteered to make a PR with the proposal demonstration in a day or two, depending on my free time. |
I would have rather made |
I don't remember why it was done this way. Let me see if @1st1 remembers. I betcha there's a deep reason. |
I'd be +1 for In #91887 @bdarnell @bast0006 did some good code archaeology on Further, it sounds like some of the original API to facilitate this didn't survive, like the ability to get "done" tasks and I hope most of the low-level debugging is now complete. So, perhaps now is a good time to change the implementation to be more obvious. |
As a next action, this would be a good issue to discuss in detail at the upcoming core dev sprint. |
FYI, this issue is now largely fixed since tasks now use a linked list in C implementation, the pure Python implementation remains to be fixed. |
Fixed by #123388 |
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:
Linked PRs
The text was updated successfully, but these errors were encountered: