Search code examples
pythonpython-asyncio

Why is my async code running in the incorrect order?


I'm trying to run some code asynchronously. My expectation is that the test coroutine should not block the print(running first) statement. This is because I've dispatched it to the event loop, and should be seeing the output of this command logged first.

import asyncio

async def test():
  await asyncio.sleep(5)
  print("I should run second")

asyncio.run(test())
print('running first')

Does anyone have any tips on how to how this code run so that print('running first') is ran before print("I should run second")? I believe this code should be non-blocking, so I'm confused as to why the order of print messages isn't matching my expectation.


Solution

  • I believe this is what you want:

    import asyncio
    
    async def test():
      await asyncio.sleep(5)
      print("I should run second")
    
    async def main():
        task1 = asyncio.create_task(test())
        print('running first')
        await task1
    
    asyncio.run(main())
    

    A more detail explaination: asyncio.run() will try to wait all of the task inside it to finish before it continues.

    In your code, you are running asyncio.run(test()) first and it will continue ONLY IF test() IS ENDED and you awaited the sleep. so test() will end after the sleep and run the print then the main print.

    This is why your code delay so long before running. The solution to it is simple. Fire the task without waiting, which is what asyncio.create_task() is doing, I created a task, fire it but wait it at the end.

    btw normally when you are using async, you will have a ton of task in a list. If you want to wait it as a list you should use gather():

    import asyncio
    
    async def test():
      await asyncio.sleep(5)
      print("I should run second")
    
    async def main():
        task_list = []
        for _ in range(100):
            task_list.append(asyncio.create_task(test()))
        print('running first')
        await asyncio.gather(*task_list)
    
    asyncio.run(main())