0

I am confused by to what extent does the following example from the Python documentation is different from a time.sleep. If you replace the asyncio.sleep with the time.sleep below, both versions last for 3 seconds, I see no difference! Can some one explain what the point of this example in the documentation is? Shouldn't the async version actually last 2 seconds instead? I understand it that both calls to say_hello practically start at the same time (that is the whole sense of asyncio.sleep, right?), so that the whole delay should be just the longest one. Help me to understand what I am understanding wrong.

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {time.strftime('%X')}")

    await say_after(1, 'hello')
    await say_after(2, 'world')

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())
Student
  • 708
  • 4
  • 11

1 Answers1

1

With time.sleep, the program would wait for the specified time before continuing to the next line. This means that the program would be blocked for the entire duration of the sleep, and cannot perform any other tasks in the meantime.

On the other hand, asyncio.sleep is a coroutine function that allows the program to continue executing other tasks while the sleep function is still running. This means that the program is not blocked, and can continue to perform other tasks in parallel.

This is important in a real-world scenario where there may be multiple tasks that need to be executed at the same time, and the program should not be blocked waiting for one task to complete. Using asyncio.sleep allows for more efficient use of resources and time.

asyncio.sleep() vs time.sleep() from the above comment does a good job explaining on a example so you might check that as well

Update: The comments in the docs to your snippet state:

The following snippet of code will print “hello” after waiting for 1 second, and then print “world” after waiting for another 2 seconds

In this example, the second say_after function call should start immediately after the first call, without waiting for it to finish. However, the asyncio.sleep function suspends the execution of the coroutine until the specified delay has passed. This means that both say_after calls run consecutively and take the total sum of the delays, which is 3 seconds in this case but it does not block the execution of other tasks that might be running concurrently.

You can make two calls for say_after so they run simultaneously which is not possible with time.sleep:

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)


async def main():
    print(f"started at {time.strftime('%X')}")
    await asyncio.gather(say_after(1, 'hello'), say_after(2, 'world'))

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

To have the program take only 2 seconds as you were expecting originally you could also use the next function in the documentation asyncio.create_task() like this:

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)


async def main():
    print(f"started at {time.strftime('%X')}")

    tasks = [asyncio.create_task(
        say_after(1, 'hello')), asyncio.create_task(say_after(2, 'world'))]
    await asyncio.gather(*tasks)

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())
Ludo
  • 152
  • 7
  • I have added an update to my question. Shouldn't the process take the longest of delays (hence last only 2 seconds), since basically both say_afters are started at the same time. – Student Jan 31 '23 at 20:54
  • @Student updated my comment, hope this helps and doesnt confuse you even more. I really suggest you may check https://stackoverflow.com/questions/56729764/asyncio-sleep-vs-time-sleep if that is the case – Ludo Jan 31 '23 at 21:25