Futures

One of the most important elements in asyncio are futures, which represent a process that has not yet finished. A future is an object that is supposed to have a result in the future and represents uncompleted tasks.

A good example for starting with asyncio is collecting all of the responses from its URL list and performing post-processing on them. In the following example, we are using an asyncio future object and passing whole lists of future objects as tasks to be executed in the loop. Each future is a task that is going to be executed in the loop.

For more information on asyncio futures, check out the following documentation: https://docs.python.org/3/library/asyncio-task.html#future.

You can find the following code in the future_example.py file:

#!/usr/local/bin/python3

import asyncio
from aiohttp import ClientSession
import time

async def fetch(url, session):
async with session.get(url) as response:
# async operation must be preceded by await
return await response.read()

In the following code block, we are defining our execute method, which uses the ClientSession() class from the aiothttp package for resolving requests and getting responses with the async-await pattern:

async def execute(loop):
url = "http://httpbin.org/{}"
tasks = []
sites = ['headers','ip','user-agent']
# Fetch all responses within one Client session,
# keep connection alive for all requests.
async with ClientSession() as session:
for site in sites:
task = asyncio.ensure_future(fetch(url.format(site), session))
tasks.append(task)
# async operation must be preceded by await
responses = await asyncio.gather(*tasks)
# you now have all response bodies in this variable
for response in responses:
print(response.decode())

This is our main program, which initializes the event loop and calls the execute method inside the context created by the asyncio.ensure_future() method. This is shown as follows: 

if __name__ == '__main__':
t1 = time.time()
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(execute(loop))
loop.run_until_complete(future)
print(time.time() - t1, 'seconds passed')

Among the main methods we are using, we can highlight the following:

  • loop.run_until_complete() is the event loop that runs until a particular coroutine completes.
  • asyncio.gather() collects future objects in one place and waits for all of them to finish.
  • response.read() is an async operation. This means that it does not return a result immediately—it just returns a generator. This generator still needs to be called and executed, but this does not happen by default; we need to use await.

The following is the output of the previous script, where we can see headers for request and response:

{
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "Python/3.7 aiohttp/3.5.4"
}
}

{
"origin": "192.113.65.10, 192.113.65.10"
}

{
"user-agent": "Python/3.7 aiohttp/3.5.4"
}

0.4722881317138672 seconds passed

In this script, we were introduced to the await keyword, which is one of the fundamental building blocks of asynchronous programs in Python. The await keyword tells the Python interpreter that the succeeding expression is going to take some time to evaluate so that it can spend that time on other tasks.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset