Hands-On Reactive Programming with Python
上QQ阅读APP看书,第一时间看更新

Coroutines

Coroutines are another building block of AsyncIO. Coroutines were already covered in detail previously in this chapter. A coroutine is basically a generator with syntactic sugar. A coroutine is an asynchronous function that can be interrupted and resumed at specific locations. A coroutine is declared the same way as a function, but with the async keyword prefixed:

import datetime

async def wait(delay):
now = datetime.datetime.now()
print("wait for {} seconds at {}:{}:{}".format(
delay, now.hour, now.minute, now.second))
return True

This coroutine just returns True for now. The first big difference between a coroutine and a regular function is the fact that its code is not immediately executed when the coroutine is called. Instead, a coroutine object is returned:

wait(3)
<coroutine object wait at 0x10b807570>

The second difference between a coroutine and a function is the fact that a coroutine can call another coroutine, and so it can be interrupted and resumed at these code locations. Calling another coroutine, and asynchronously waiting for its result, is done with the await keyword. For example, the wait coroutine can wait for some time without blocking the whole program by using the asyncio.sleep coroutine:

import asyncio
import datetime

async def wait(delay):
now = datetime.datetime.now()
print("wait for {} seconds at {}:{}:{}".format(
delay, now.hour, now.minute, now.second))
await asyncio.sleep(delay)
now = datetime.datetime.now()
print("waited for {} seconds at {}:{}:{}".format(
delay, now.hour, now.minute, now.second))
return True

The await syntax indicates to the Python interpreter that when the sleep coroutine is called, then the execution of the wait coroutine must be interrupted. The execution of the wait coroutine resumes when the sleep coroutine completes. This means that the wait coroutine continues its execution after the await expression, with all its context (local variables and closures) being restored. So, let's try to run this wait coroutine. Executing a coroutine and retrieving its result is done with the await keyword, used before the call itself. But there is a catch; this works only inside of a coroutine. So, trying to use the await keyword outside of a coroutine does not work:

await wait(3)
File "<stdin>", line 1
await wait(3)
^
SyntaxError: invalid syntax

This is the typical chicken and egg issue. A coroutine can only be called by another coroutine. So how can someone bootstrap a first call to a coroutine? This is the role of the event loop.