17

The following example from Python in a Nutshell sets x to 23 after a delay of a second and a half:

@asyncio.coroutine
def delayed_result(delay, result):
  yield from asyncio.sleep(delay)
  return result

loop = asyncio.get_event_loop()
x = loop.run_until_complete(delayed_result(1.5, 23))

I feel difficult to understand what yield from asyncio.sleep(delay) does.

From https://docs.python.org/3/library/asyncio-task.html#asyncio.sleep

Coroutine asyncio.sleep(delay, result=None, *, loop=None)

Create a coroutine that completes after a given time (in seconds). If result is provided, it is produced to the caller when the coroutine completes.

So asyncio.sleep(delay) returns a coroutine object.

What does a coroutine object "completes" mean?

What values does yield from asyncio.sleep(delay) provide to the main program?

Thanks.

Tim
  • 1
  • 141
  • 372
  • 590

2 Answers2

23

The following line of code :

time.sleep(5)

...freezes the execution of your code for 5 seconds. Nothing further is computed or executed until the sleep function has completed it's 5 second nap as the application can't proceed without the sleep function returning control to the caller. This is called synchronous programming, when there is no mechanism for the application to change its focus and complete other tasks in periods of waiting such as waiting for the results of a call to a database, a web api or as in this case the sleep function. In synchronous programming there is no need for an event loop as there is no expectation that the application manages its time nor that it switches tasks for efficiency gains.

The following code :

asyncio.sleep(5)

... is part of the asyncio library, designed for asynchronous programming where an event loop is assigned tasks to be competed and it (the event loop) monitors the state of all its tasks and switches from one to another with the objective of minimising the amount of time idle/waiting. This is not threading where multiple processes are being executed simultaneously, this is merely optimising task execution so the CPU is not left idle, therefore gaining hugely reduced overall execution times.

The yield from keyword (python 3.5 onwards await keyword can be used) is the moment where the event loop has the chance to leave one task to finish (e.g. While a query is returned from a database call) and focus on another task which the event loop is aware of and can actually be computed/executed in the meantime.

@asyncio.coroutine decorator + yield from is compatible with python 3.5 onwards but using the new keyword async def to define an asyncronous coroutine and the await keyword within it to allow the event loop to evaluate switching to another task is the common and future proof way to go if you're 3.5 or above.

Asyncronous python can be quite difficult to get your head round but there are a number of excellent pycon talks on the subject from the previous few years - look for one on Youtube and if course read the docs

user3535074
  • 1,268
  • 8
  • 26
  • 48
0

yield from is python3.4 syntax for 3.5 await which will probably make more sense.

"completes" just means the task from the coroutine has finished.

In this case you want to use the async sleep so you can computer other tasks while the sleep-task is running, it makes more sense if you have other parallel tasks/coroutines running.

zython
  • 1,176
  • 4
  • 22
  • 50
  • Thanks. (1) by ""completes" just means the task is finished." do you mean the coroutine object (which was returned by `sleep`) completes its execution? (2) could you give an example of "have other parallel tasks/coroutines running"? – Tim Sep 13 '17 at 22:59
  • (3) " If result is provided, it is produced to the caller when the coroutine completes." Since `result` is `1.5` here, why is `3` instead of `1.5` assigned to `x`? – Tim Sep 13 '17 at 23:02
  • (2) you can build up lists of tasks of async functions which will run parallel. if you use async sleep it will only sleep one task if you use synchro sleep it will sleep the whole process (1) yes – zython Sep 13 '17 at 23:03
  • (3) i dont follow, where do you get these values from ? – zython Sep 13 '17 at 23:07
  • Sorry some typo. Should be: " If result is provided, it is produced to the caller when the coroutine completes." Since result is 1.5 here, why is 23 instead of 1.5 assigned to `x`? – Tim Sep 13 '17 at 23:08
  • result is not 1.5 `def delayed_result(delay, result)` `loop.run_until_complete(delayed_result(1.5, 23))` – zython Sep 13 '17 at 23:10
  • What values does `yield from asyncio.sleep(delay)` provide to the main program? – Tim Sep 13 '17 at 23:11
  • no value is returned, the coroutine just sleeps for the value entered – zython Sep 13 '17 at 23:12
  • Thanks. What does the coroutine object returned by `sleep` do/execute before it completes? – Tim Sep 13 '17 at 23:13
  • I just checked with the documentation, you have to pass the delay AND the result so the async sleep returns your the result https://docs.python.org/3/library/asyncio-task.html#asyncio.sleep – zython Sep 13 '17 at 23:17
  • Thanks. Could you explain "you can build up lists of tasks of async functions which will run parallel. if you use async sleep it will only sleep one task if you use synchro sleep it will sleep the whole process "? I can't figure out how async is useful – Tim Sep 13 '17 at 23:38
  • with asyncio.ensurefuture() you can create a task, if you create a multiple of those tasks and pass them to a `await asyncio.gather(tasks)` statement they will execute in parallel thus allowing for immense speedups in some cases, now sleep in the synchronous version will halt the entire python interpreter for some time while asyncio.sleep will only sleep that one task – zython Sep 13 '17 at 23:49