2

I'm running this code in Python 3.7.3

import asyncio

async def fun(time):
    print(f"will wait for {time}")
    await asyncio.sleep(time)
    print(f"done waiting for {time}")

async def async_cenas():
    t1 = asyncio.create_task(fun(1))
    print("after 1")
    t2 = asyncio.create_task(fun(2))
    print("after 2")

def main():
    t1 = asyncio.run(async_cenas())
    print("ok main")
    print(t1)

if __name__ == '__main__':
    main()
    print("finished __name__")

And getting this output:

after 1
after 2
will wait for 1
will wait for 2
ok main
None
finished __name__

I was expecting to see also:

done waiting for 1
done waiting for 2

I.e., why was expecting asyncio.run(X) would wait for the coroutines to complete before proceeding.

Fernando César
  • 681
  • 1
  • 8
  • 16
  • What is your question? `run` waits for main coroutine, and than cancel all the other tasks, you could read the [implementation](https://github.com/python/cpython/blob/master/Lib/asyncio/runners.py) – NobbyNobbs Mar 20 '21 at 19:55
  • Thanks for the link to the source, that helped @NobbyNobbs – Fernando César Mar 20 '21 at 23:20
  • @larsks `run_until_complete` will have the exact same "problem" of waiting for only what you've told it to wait for. In fact, `asyncio.run` is a fairly straightforward wrapper around `loop.run_until_complete`. – user4815162342 Mar 21 '21 at 00:15

1 Answers1

6

If you want to wait for the completion of all tasks spawned by the create_task, then you need to do it explicitly by, for example, just await for them in turn or asyncio facilities like gather or wait (the difference is described here). Otherwise, they will be canceled by the asyncio.run when exiting the main coroutine, which is passed to asyncio.run.

Example:

import asyncio

async def fun(time):
    print(f"will wait for {time}")
    await asyncio.sleep(time)
    print(f"done waiting for {time}")

async def async_cenas():
    t1 = asyncio.create_task(fun(1))
    print("after 1")
    t2 = asyncio.create_task(fun(2))
    print("after 2")
    await asyncio.wait({t1, t2}, return_when=asyncio.ALL_COMPLETED)
    # or just
    # await t1
    # await t2

def main():
    t1 = asyncio.run(async_cenas())
    print("ok main")
    print(t1)

if __name__ == '__main__':
    main()
    print("finished __name__")
after 1
after 2
will wait for 1
will wait for 2
done waiting for 1
done waiting for 2
ok main
None
finished __name__

alex_noname
  • 26,459
  • 5
  • 69
  • 86