Книга: Learning Concurrency in Python
Назад: Coroutines
Дальше: Output

Chaining coroutines

In certain situations, you may wish to chain the calling of your coroutines together in order to achieve maximum performance within your Python systems.

The official documentation again has an excellent code sample that demonstrates this concept of chaining very well. Within this code, we have two distinct coroutines denoted by async def. The compute coroutine returns the summation of x + y after having performed a blocking sleep for 1 second.

Let's assume, however, that we want to rely on the result of a second coroutine within our first coroutine as follows:

import asyncio

async def compute(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(1.0)
return x + y

async def print_sum(x, y):
result = compute(x, y)
print("%s + %s = %s" % (x, y, result))

loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()

Upon execution of the preceding script, you should see that the following is outputted:

$ python3.6 06_chainCoroutine.py
1 + 2 = <coroutine object compute at 0x1031fc0f8>
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/events.py:126: RuntimeWarning: coroutine 'compute' was never awaited
self._callback(*self._args)

This essentially states that the compute function within our print_sum() method call was never awaited and the program tried to carry on as if it had received the result.

In order to overcome this particular issue, we need to utilize the await keyword. This await keyword blocks the event loop from proceeding any further until the called coroutine returns its result. The main drawback of this, however, is that, in this particular example, we lose the benefits of asynchronicity and we are back to standard synchronous execution. It's up to you to determine where the use of await is necessary as it does give you very quick and easy deterministic execution but you take hits on performance.

The print_sum coroutine instantiates a result variable that is equal to whatever the compute coroutine returns:

import asyncio

async def compute(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(1.0)
return x + y

async def print_sum(x, y):
result = await compute(x, y)
print("%s + %s = %s" % (x, y, result))

loop = asyncio.get_event_loop()
loop.run_until_complete(print_sum(1, 2))
loop.close()

If we look at the sequence diagram that comes from the official documentation for this program, you should be able to see clearly how this chaining of coroutines is broken down in real terms:

Source: https://docs.python.org/3/library/asyncio-task.html
Назад: Coroutines
Дальше: Output