.. _asyncio: Introduction to asyncio ======================= Asyncio is the part of the Python standard library that provides an event loop with IO (input/output) operations. It exists to allow concurrent programming in Python, whereby the event loop switches to another task whilst the previous task waits on IO. This concurrency allows for greater CPU utilisation and hence greater throughput performance. The easiest way to understand this is to consider something concrete, namely a demonstrative simulation In the following we fetch a url with a simulated IO delay, .. code-block:: python import asyncio async def simulated_fetch(url, delay): await asyncio.sleep(delay) print(f"Fetched {url} after {delay}") return f"{url}" def main(): loop = asyncio.get_event_loop() results = loop.run_until_complete(asyncio.gather( simulated_fetch('http://google.com', 2), simulated_fetch('http://bbc.co.uk', 1), )) print(results) you should see the following output, >>> Fetched http://bbc.co.uk after 1 >>> Fetched http://google.com after 2 >>> ['http://google.com', 'http://bbc.co.uk'] which indicates that despite calling the ``google.com`` fetch first, the ``bbc.co.uk`` actually completed first i.e. the code ran concurrently. Additionally the code runs in a little over 2 seconds rather than over 3 as expected with synchronous code. Relevance to web servers ------------------------ Web servers by definition do IO, in that they receive and respond to requests from the network. This means that asyncio is a very good fit even if the code within the framework does no IO itself. Yet in practice IO is present, for example when loading a template from a file, or contacting a database or another server. Common pitfalls --------------- It is very easy to await the wrong thing, for example, .. code-block:: python await awaitable.attribute will not await the ``awaitable`` object as you might expect, but rather attempt to resolve the attribute and then await it. This is quite commonly seen as, .. code-block:: python await request.form.get('key') which fails with an error that the coroutine wrapper has no get attribute. To work around this simply use brackets to indicate what must be awaited first, .. code-block:: python (await awaitable).attribute (await request.form).get('key')