Python async/await: introduction

Python 3.5 is coming up soon with async and await built-in keywords. Let's get excited with a couple of simple examples showing off how to use this new syntax.

For those unaware of asynchronous programming, we could say it's a way to achieve a certain level of multi-tasking within a single process or thread. It leverages the fact that our typical processes spend a lot of their time waiting for input/ouput (I/O) operations to complete. The kind of operation involving I/O includes receiving requests from clients, reading files, querying a database server or talking to a RESTful API. Instead of waiting for each I/O operation to complete before starting the next one, asynchronous programming allow a single process to schedule several such operations in parallel.

This is similar to how you may prepare your breakfast. You probably don't wait for coffee or tea to be ready before starting your toaster or rice cooker. You start both operations in parallel and get notified by an event (kettle whistling, bread popping out) when they've completed. This way you can multitask effectively even though you're a single "process".

Let's start with a Hello World example using asyncio.sleep to simulate slow I/O operations and asyncio.wait to launch them in parallel. This is how it would look like before Python 3.5:

Now for a slightly more realistic example, we'll implement a web server that makes sub-requests to external HTTP services. We could imagine it evolving into a website monitoring app. We'll use aiohttp, an HTTP client/server for asyncio:

importasyncioimportaiohttpfromaiohttpimportwebimportjsonWEBSITES=['http://example.com/','http://dummy-a98x3.org','http://example.net/']asyncdefhandle(request):# Fire up 3 requests in parallelcoroutines=[aiohttp.request('get',website)forwebsiteinWEBSITES]# Wait for those requests to completeresults=awaitasyncio.gather(*coroutines,return_exceptions=True)# Analyze resultsresponse_data={website:notisinstance(result,Exception)andresult.status==200forwebsite,resultinzip(WEBSITES,results)}# Build JSON responsebody=json.dumps(response_data).encode('utf-8')returnweb.Response(body=body,content_type="application/json")loop=asyncio.get_event_loop()app=web.Application(loop=loop)app.router.add_route('GET','/',handle)server=loop.create_server(app.make_handler(),'127.0.0.1',8000)print("Server started at http://127.0.0.1:8000")loop.run_until_complete(server)try:loop.run_forever()exceptKeyboardInterrupt:pass