Skip to content

Conversation

@graingert
Copy link
Contributor

@graingert graingert commented Jan 24, 2025

@graingert graingert force-pushed the staggered-race-add-to-awaited-by branch from ddeeee9 to 7626ae4 Compare January 24, 2025 10:43
@graingert graingert marked this pull request as ready for review January 24, 2025 10:55
"""
# TODO: when we have aiter() and anext(), allow async iterables in coro_fns.
loop = loop or events.get_running_loop()
parent_task = tasks.current_task(loop)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we're not running in a task? Should we assert that this is non-None?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one possible outcome is that there's no task or running loop:

import asyncio.staggered

async def main():
    async def asyncfn():
        pass

    await asyncio.staggered.staggered_race([asyncfn, asyncfn], delay=None)

main().__await__().send(None)

we get a nice traceback, saying that:

./python demo.py
Traceback (most recent call last):
  File "/home/graingert/projects/cpython/demo.py", line 9, in <module>
    main().__await__().send(None)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/home/graingert/projects/cpython/demo.py", line 7, in main
    await asyncio.staggered.staggered_race([asyncfn, asyncfn], delay=None)
  File "/home/graingert/projects/cpython/Lib/asyncio/staggered.py", line 66, in staggered_race
    loop = loop or events.get_running_loop()
                   ~~~~~~~~~~~~~~~~~~~~~~~^^
RuntimeError: no running event loop

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you manually pass a loop, and step the coroutine outside of a task:

import asyncio.staggered

async def main(loop):
    async def asyncfn():
        print("hello")

    await asyncio.staggered.staggered_race([asyncfn, asyncfn], delay=None, loop=loop)
    return "world"

loop = asyncio.EventLoop()
coro = main(loop).__await__()
f = coro.send(None)
loop.run_until_complete(f)
try:
    coro.send(None)
except StopIteration as e:
    print(e.value)

by some miracle it all works, this is because future_add_to_awaited_by and future_discard_from_awaited_by is noop if any arg is not a future (eg is None) and we don't have any further use of the parent task

./python demo.py
hello
world

so we should probably leave it like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's worth testing this usecase though

t.cancel()

propagate_cancellation_error = None
try:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above this--for cancelling all the coroutines, future_discard_from_awaited_by should get called, right?

Copy link
Contributor Author

@graingert graingert Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah add_done_callback callbacks are called on cancellation, so it will get called

Copy link
Member

@ZeroIntensity ZeroIntensity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as well.

@kumaraditya303 kumaraditya303 merged commit fccbfc4 into python:main Jan 26, 2025
38 checks passed
@graingert graingert deleted the staggered-race-add-to-awaited-by branch January 26, 2025 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants