GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — gh-108951: add TaskGroup.cancel() by belm0 · Pull Request #127214 · python/cpython Conversation
|
|
|
||
| async def test_taskgroup_stop_children(self): | ||
| async with asyncio.TaskGroup() as tg: | ||
| tg.create_task(asyncio.sleep(math.inf)) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Maybe these tasks should look like this?
async def task(results, num): results.append(num) await asyncio.sleep(math.inf) results.append(-num)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
So we can assert what was in results
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
For this particular test, I chose a different test approach, which is to wrap in asyncio.timeout().
For the other tests using count, I'm not sure it's much value, since the test code is only a few lines and there is only one possible path through it. So count result of 0, 1, or 2 each have deterministic meaning that's obvious by looking at the code.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Co-authored-by: sobolevn <[email protected]>
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Why call it TaskGroup.stop() and not TaskGroup.cancel()? I'd be more in favor of the latter name.
Short-circuiting of task groups is a very common, useful, and normal, so make it a first-class operation.
Any evidence of this statement? I'd like you to write up technical motivation + examples. That will be useful for the docs.
And speaking of the documentation, you should also show some recipies of how this would be used. Like are you supposed to use this API from within the task group async with clause? Or can you pass the task group to some remote task?
I haven't reviewed the actual implementation in detail yet.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
This doesn't work in the case that the body of the task group throws an exception, as in this code: async def test_taskgroup_throw_inside(self): class MyError(RuntimeError): pass should_get_here = False try: async with asyncio.TaskGroup() as tg: tg.create_task(asyncio.sleep(0.1)) tg.stop() self.assertEqual(asyncio.current_task().cancelling(), 1) raise MyError self.fail() # <-- reaches here instead of raising ExceptionGroup([MyError()]) except* MyError: self.assertEqual(asyncio.current_task().cancelling(), 0) should_get_here = True self.assertTrue(should_get_here) The problem is that the new code in the if et is not None and not issubclass(et, exceptions.CancelledError): self._errors.append(exc) One option is move these lines earlier, before the I'd still suggest my original proposal (see the issue) where you just add a single line As a separate point, I'd suggest that the tests could do with a few more checks that |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I'd also prefer
In trio the equivalent is I have years experience developing a non-trivial, production async app, which I've presented at PyCon JP. Anecdotally, I can't imagine how painful and unproductive it would be to not have short circuiting of task groups.
All is on the table: stop from within the TaskGroup body, from a child, from some other entity you've passed the bound stop() method to. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Well, that's exactly what it does, isn't it? The fact that the cancelled taskgroup catches the Also, trio and anyio already call this operation |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
7e25c26 to
f077241
Compare
|
|
||
| Ways to use :meth:`cancel`: | ||
|
|
||
| * call it from the task group body based on some condition or event |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Probably you want code examples for all of these?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
@belm0 -- I take it you are not planning to add cancel messages and you are not planning to add more examples to the docs? Once you confirm that I will approve and merge. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I take it you are not planning to add cancel messages and you are not planning to add more examples to the docs?
I've been working through the PR's items in some priority order and hadn't reached those (you've caught me in the middle of quite a hectic week).
I've just committed a few tweaks to the added docs, but no cancel examples. Task groups are quite powerful and I've seen other async libs build up examples over several pages. The existing docs are lacking here so I don't have the foundation to add the cancel() examples. Expanded TaskGroup docs need to be written by someone who lives and breathes asyncio daily and is intimate with the library's nuances (that was once me for trio, but not asyncio).
For cancel(msg) I've made another comment on that thread-- not being bought into the idea I'm reluctant to take on the extra impl/doc/testing in this PR.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM; I'll merge it.
I do have some nits on the docs still but they don't need to hold up the merge.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
@belm0 Thanks for your perseverance! This looks like a useful addition. Additionally we probably need a "what's new" entry, and I have some nits on the docs (mostly that I find the term "short-circuit" confusing, I've not seen it in the context of asyncio or task groups). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I was unaware of this effort. Good to see this being added. I have some nits on the docs, though. It says:
As opposed to what? And the news item:
Surely it will exit with errors if the tasks raise any non-cancellation exceptions after |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I think that's supposed to be "as opposed to cancelling the task in which the taskgroup is running". |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
But it does cancel the host task too? It just uncancels it when exiting the task group. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
That would be … quite non-productive. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
AnyIO task groups and Trio nurseries do that too. Do you find that unproductive? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@agronholm Are you still talking about the docs or are you now disagreeing with how it works? If the former, feel free to send a PR. If the latter, I suggest reading the full discussion in the issue first, and then everything here. Use an AI to summary if you want to. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
I'm not trying to argue about the functionality, I only have some slight problems about the wordings and how they could be misleading. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@agronholm Misunderstanding here. "Cancel the host task", in asyncio parlance, meant cancelling the task directly, not the taskgroup. in that case the taskgroup won't eat the cancellation exception. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There is no way to accomplish this on asyncio without calling |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Fixes python#108951 Co-authored-by: sobolevn <[email protected]> Co-authored-by: Andrew Svetlov <[email protected]> Co-authored-by: Guido van Rossum <[email protected]>
|
whatsnew entry and minimal doc tweaks in #149031 |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.