The asyncio library in Python provides a framework for writing single-threaded concurrent code using coroutines, which are a type of asynchronous function. It allows you to manage asynchronous operations easily and is suitable for I/O-bound and high-level structured network code.
Key Concepts
- Event Loop: The core of every
asyncioapplication. It runs asynchronous tasks and callbacks, performs network I/O operations, and runs subprocesses. - Coroutines: Special functions defined with
async def, which can useawaitto call other asynchronous functions. - Tasks: A higher-level way to manage coroutines. They allow you to schedule coroutines concurrently.
- Futures: Objects that represent the result of an asynchronous operation, typically managed by the event loop.
- Streams: High-level APIs for working with network connections.
Basic Usage
Here’s a simple example of using asyncio to run a couple of coroutines:
import asyncio
async def say_hello():
await asyncio.sleep(1)
print("Hello")
async def say_world():
await asyncio.sleep(1)
print("World")
async def main():
await asyncio.gather(
say_hello(),
say_world(),
)
asyncio.run(main())
Creating Tasks
You can use asyncio.create_task() to schedule a coroutine to run concurrently:
async def task_example():
print("Task started")
await asyncio.sleep(2)
print("Task finished")
async def main():
task = asyncio.create_task(task_example())
await task
asyncio.run(main())
Anticipate Futures
Futures represent a value that may not be available yet. You can create and wait for a future:
import asyncio
async def set_future(fut):
await asyncio.sleep(2)
fut.set_result("Future is done")
async def main():
fut = asyncio.Future()
await asyncio.gather(set_future(fut))
print(fut.result())
asyncio.run(main())
streams
Working with TCP streams using asyncio is straightforward:
import asyncio
async def handle_client(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info(‘peername’)
print(f"Received {message} from {addr}")
writer.write(data)
await writer.drain()
writer.close()
async def main():
server = await asyncio.start_server(handle_client, ‘127.0.0.1’, 8888)
addr = server.sockets[0].getsockname()
print(f’Serving on {addr}’)
async with server:
await server.serve_forever()
asyncio.run(main())
Exception Handling
You can handle exceptions within asyncio tasks:
async def error_task():
raise ValueError("An example error")
async def main():
task = asyncio.create_task(error_task())
try:
await task
except ValueError as e:
print(f"Caught an exception: {e}")
asyncio.run(main())
Integration with Other Libraries
asyncio can be integrated with various libraries, including web frameworks like FastAPI, databases, and more. This allows for highly responsive applications that can handle many tasks concurrently.
Useful Functions
asyncio.sleep(): Sleep for a given number of seconds.asyncio.gather(): Run multiple coroutines concurrently and wait for them to complete.asyncio.wait_for(): Wait for a coroutine with a timeout.asyncio.shield(): Protect a task from cancellation.asyncio.run(): Run an event loop until the given coroutine completes.
