-
-
Notifications
You must be signed in to change notification settings - Fork 8.4k
extmod/uasyncio: Add asyncio.shield() #5928
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
Conversation
Add shield() support to Task class
Add shield() coroutine
I just realized that my implementation is actually wrong because shield() needs to return a Task. Therefore it fails in some scenarios. Will update as soon as I found a fix. |
extmod/uasyncio/task.py
Outdated
@@ -128,6 +128,7 @@ def __init__(self, coro, globals=None): | |||
self.ph_child_last = None # Paring heap | |||
self.ph_next = None # Paring heap | |||
self.ph_rightmost_parent = None # Paring heap | |||
self.shield = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this here means increasing the size of all tasks, even those that don't use shield, and would ideally be avoided. In the C implementation of Task
you can see that the size of the task is 8 words, so increasing it by one will mean it now needs 3 GC blocks rather than 2 (there are 4 words per GC block). Would be better to find a way to not need this variable....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely. It's meant as a proof-of-concept. You'll know how to optmizie it better than I do.
But currently I am having trouble getting it to work correctly with shield() returning a Task object. An oversight from the start, so this code (except for self.shield=False) is actually not how it will work.. You can ignore it for now.
Now it should work correctly! Took me a while to figure it out but now it actually looks like a fairly small change to "task.py". Only CPython difference in the tests is the cancellation order of wait_for. |
I put shield() back into funcs.py and changed the way Task.shield is assigned to the same way Task.waiting is done. Testcases updated and extended. The result is now the same as Cpython even in wait_for cases if the fix in #5931 is applied. |
Little bugfix setting shield correctly after task finished (actually not even needed because that tasks are being destroyed afterwards anyways).
Thanks for updating this. It is quite clean although it still requires an additional entry in the It would be good to look for an alternative implementation of shield that did not need any modifications to the existing core code (but I'm not asking you to do that!). With #6667, wait-for can be fixed without shield, but IMO shield is still useful in its own right. |
Thanks for taking a look at this and wait_for!
|
Except that adding a new entry to |
This needs a different solution that doesn't require adding a member to the |
This PR adds asyncio.shield() to uasyncio which prevents the shielded task from being cancelled if shield() gets cancelled.
It includes testcases too.
It does however not modify _uasyncio/tasks which is not written in python.
Also I don't know how happy you are with the test-case format I chose or with the way shield is integrated. Consider it a "proof-of-concept".
Additionally there is one test "test_cancel_wait_for_shield()" which gives a different order than CPython due to the differences in wait_for.