Python Advanced - Asynchronous Programming with Asyncio
Understanding asynchronous programming with asyncio
Asynchronous programming allows you to write code that performs tasks concurrently, making efficient use of system resources. Python's asyncio
module provides tools to write asynchronous code using coroutines, tasks, and event loops. This tutorial explores how to use asyncio
for asynchronous programming in Python.
Key Points:
- Asynchronous programming allows concurrent execution of tasks.
- Python's
asyncio
module provides support for asynchronous programming using coroutines, tasks, and event loops. - Coroutines are defined using
async def
and are scheduled using the event loop.
Coroutines
Coroutines are the building blocks of asynchronous code. They are defined using the async def
syntax and can be awaited using the await
keyword:
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
# Running the coroutine
asyncio.run(say_hello())
In this example, the say_hello
coroutine prints "Hello", waits for 1 second, and then prints "World". The coroutine is run using asyncio.run()
.
Creating and Running Tasks
Tasks are used to schedule the execution of coroutines. You can create tasks using the asyncio.create_task()
function:
import asyncio
async def say(what, when):
await asyncio.sleep(when)
print(what)
async def main():
task1 = asyncio.create_task(say("Hello", 2))
task2 = asyncio.create_task(say("World", 1))
print("Waiting for tasks to complete...")
await task1
await task2
asyncio.run(main())
In this example, two tasks are created to run the say
coroutine with different delays. The main
coroutine waits for both tasks to complete.
Event Loop
The event loop manages the execution of asynchronous tasks. You can get the current event loop and run coroutines or tasks using the event loop:
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
loop = asyncio.get_event_loop()
loop.run_until_complete(say_hello())
loop.close()
In this example, the event loop is obtained using asyncio.get_event_loop()
, and the say_hello
coroutine is run using run_until_complete()
. The event loop is closed after the coroutine completes.
Gathering Tasks
You can run multiple coroutines concurrently and wait for them to complete using asyncio.gather()
:
import asyncio
async def say(what, when):
await asyncio.sleep(when)
print(what)
async def main():
await asyncio.gather(
say("Hello", 2),
say("World", 1)
)
asyncio.run(main())
In this example, asyncio.gather()
is used to run the say
coroutine concurrently with different delays. The main
coroutine waits for both coroutines to complete.
Handling Exceptions
You can handle exceptions in asynchronous code using try-except blocks within coroutines:
import asyncio
async def faulty_coroutine():
await asyncio.sleep(1)
raise ValueError("An error occurred")
async def main():
try:
await faulty_coroutine()
except ValueError as e:
print(f"Caught an exception: {e}")
asyncio.run(main())
In this example, the faulty_coroutine
raises a ValueError
after a delay. The main
coroutine catches and handles the exception.
Using Async Context Managers
Async context managers are used to manage resources that need to be cleaned up. They are defined using the async with
syntax:
import asyncio
class AsyncContextManager:
async def __aenter__(self):
print("Entering context")
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
print("Exiting context")
async def main():
async with AsyncContextManager():
print("Inside context")
asyncio.run(main())
In this example, the AsyncContextManager
class defines an async context manager. The main
coroutine uses the context manager with the async with
syntax.
Summary
In this tutorial, you learned about asynchronous programming with asyncio
in Python. Asynchronous programming allows concurrent execution of tasks, making efficient use of system resources. You explored coroutines, tasks, event loops, gathering tasks, handling exceptions, and using async context managers. Understanding asynchronous programming is essential for building efficient and responsive applications in Python.