async Python
Introduction
Often, hardware I/O bottlenecks a program's latency, thoroughput, and/or run time. That is, file and network actions slow down the program most significantly. A program often consists of many independent file and network actions. In those cases, Python gives us the async
construct for running the actions asynchronously.
Syntax
In general, async
Python programming involves adding the keyword async
in front of the non-asynchronous version. Instead of def
, use async def
. Instead of with
, use async with
. Finally, instead of for
, use async for
.
Let's look at some examples for the bottlenecks I mentioned before.
async
file I/O
In general, to read files:
from aiofile import AIOFile, LineReader
async def async_read_whole(file_name):
async with AIOFile(file_name, "r") as afp:
print(await afp.read())
async def async_read_lines(file_name):
async with AIOFile(file_name, "r") as afp:
async for line in LineReader(afp):
print(line)
I'll cover await
in my next post in more detail. For now, know that we should await
every async
function call.
To write files:
from aiofile import AIOFile, Writer
async def async_write(file_name):
async with AIOFile(file_name, "w") as afp:
writer = Writer(afp)
await writer("Hello")
await writer(" ")
await writer("World")
await afp.fsync()
The fsync
call syncs changes to the file so other accessors can see those changes.
async
network I/O
To make network requests:
import asyncio
import aiohttp
async def async_get(session, url):
async with session.get(url) as response:
return await response.text()
async def async_main():
urls = [
"https://en.wikipedia.org/wiki/Async/await",
"https://en.wikipedia.org/wiki/Coroutine",
"https://en.wikipedia.org/wiki/Event_loop",
]
async with aiohttp.ClientSession() as session:
response_coros = list(map(lambda url: async_get(session, url), urls))
for response_coro in asyncio.as_completed(response_coros):
response_text = await response_coro
print(response_text[:144])
A couple things to note:
- We reuse
session
to avoid redundantly establishing network connections. - The
asyncio.as_completed
pattern avoidsawait
-ing eachasync
request to complete before the nextasync
request, which would negate the benefit ofasync
. - We can replace
get
insession.get
with any HTTP request method, e.g.post
.
Conclusion
Hopefully, this provides you some good introductory motivation and examples for async
programming in Python.