Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I await the same Task multiple times in Python?

I need to do a lot of work, but luckily it's easy to decouple into different tasks for asynchronous execution. Some of those depend on each other, and it's perfectly clear to me how on task can await multiple others to get their results. However, I don't know how I can have multiple different tasks await the same coroutine, and both get the result. The Documentation also doesn't mention this case as far as I can find. Consider the following minimal example:

from asyncio import create_task, gather

async def TaskA():
    ...  # This is clear
    return result

async def TaskB(task_a):
    task_a_result = await task_a
    ...  # So is this
    return result

async def TaskC(task_a):
    task_a_result = await task_a
    ...  # But can I even do this? 
    return result

async def main():
    task_a = create_task(TaskA())
    task_b = create_task(TaskB(task_a))
    task_c = create_task(TaskC(task_a))
    gather(task_b, task_c)  # Can I include task_a here to signal the intent of "wait for all tasks"?

For the actual script, all tasks do some database operations, some of which involve foreign keys, and therefore depend on other tables already being filled. Some depend on the same table. I definitely need:

  1. All tasks run once, and only once
  2. Some tasks are dependent on others being done before starting.

In brief, the question is, does this work? Can I await the same instantiated coroutine multiple times, and get the result every time? Or do I need to put awaits in main(), and pass the result? (which is the current setup, and I don't like it.)

like image 338
Gloweye Avatar asked May 08 '26 10:05

Gloweye


1 Answers

You can await the same task multiple times:

from asyncio import create_task, gather, run


async def coro_a():
    print("executing coro a")
    return 'a'


async def coro_b(task_a):
    task_a_result = await task_a
    print("from coro_b: ", task_a_result)
    return 'b'


async def coro_c(task_a):
    task_a_result = await task_a
    print("from coro_a: ", task_a_result)
    return 'c'


async def main():
    task_a = create_task(coro_a())
    print(await gather(coro_b(task_a), coro_c(task_a)))


if __name__ == "__main__":
    run(main())

Will output:

executing coro a
from coro_b:  a
from coro_a:  a
['b', 'c']

What you can not do is to await the same coroutine multiples times:

...

async def main():
    task_a = coro_a()
    print(await gather(coro_b(task_a), coro_c(task_a)))
...

Will raise RuntimeError: cannot reuse already awaited coroutine.

As long as you schedule your coroutine coro_a using create_task your code will work.

like image 163
Guillermo Soto Gómez Avatar answered May 11 '26 13:05

Guillermo Soto Gómez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!