在 Python 编程中,异步操作是处理 I/O 密集型任务(如网络请求、文件读写等)的一种高效方式。通过异步操作,程序可以在等待 I/O 操作完成的同时执行其他任务,从而显著提高整体性能。Python 3.5 引入了 async 和 await 关键字,使得编写异步代码变得更加直观和简洁。本文将带你深入理解这两个关键字,并通过代码和案例展示其用法。
一、异步编程基础
在深入 async 和 await 之前,我们先来了解一下异步编程的基本概念。
- 同步与异步
同步:任务按顺序执行,一个任务完成后才执行下一个任务。
异步:任务可以并发执行,不必等待一个任务完成后再执行下一个任务。 - 异步编程的优势
提高性能:在等待 I/O 操作(如网络请求)时,可以执行其他任务。
资源利用:更有效地利用系统资源,避免阻塞。 - 异步编程的难点
代码复杂度:异步代码通常比同步代码更难理解和调试。
错误处理:需要特别注意异步操作中的错误处理。
二、async 和 await 简介 async 关键字
async 关键字用于定义一个异步函数。异步函数在调用时不会立即执行,而是返回一个 awaitable 对象(通常是 Asyncio 协程)。await 关键字
await 关键字用于等待一个 awaitable 对象完成。它只能在 async 函数内部使用。当 await 一个异步函数时,当前协程会暂停执行,直到被等待的异步函数完成,然后恢复执行。
三、async 和 await 的用法
- 异步函数的定义
使用 async 关键字定义一个异步函数:
async def my_async_function():
# 异步代码
pass
- 调用异步函数
异步函数在调用时不会立即执行,而是返回一个 awaitable 对象。要等待异步函数完成,可以使用 await 关键字(通常在另一个异步函数内部):
import asyncio
async def main():
result = await my_async_function()
print(result)
注意:不能直接调用 main(),需要使用事件循环来运行它
asyncio.run(main())
- 异步函数中的 await
在异步函数内部,可以使用 await 等待其他异步函数或异步操作完成:
import asyncio
async def fetch_data_from_api():
# 模拟网络请求
await asyncio.sleep(1) # 异步等待 1 秒
return "Data from API"
async def main():
data = await fetch_data_from_api()
print(data)
asyncio.run(main())
四、异步编程中的常见模式
- 并发执行多个异步任务
使用 asyncio.gather() 可以并发执行多个异步任务:
import asyncio
async def task1():
await asyncio.sleep(1)
return "Task 1 complete"
async def task2():
await asyncio.sleep(2)
return "Task 2 complete"
async def main():
results = await asyncio.gather(task1(), task2())
print(results)
asyncio.run(main())
在这个例子中,task1 和 task2 会并发执行,而不是按顺序执行。
- 异常处理
在异步函数中,可以使用 try...except 语句来处理异常:
import asyncio
async def faulty_task():
await asyncio.sleep(1)
raise ValueError("An error occurred")
async def main():
try:
await faulty_task()
except ValueError as e:
print(f"Caught an exception: {e}")
asyncio.run(main())
- 异步上下文管理器
Python 3.7 引入了异步上下文管理器,允许在异步代码中使用 async with 语句:
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() as ctx:
await asyncio.sleep(1)
print("Inside context")
asyncio.run(main())
五、实战案例:异步网络请求
下面是一个使用 aiohttp 库进行异步网络请求的示例。aiohttp 是一个支持异步 I/O 的 HTTP 客户端/服务器库。
- 安装 aiohttp
首先,需要安装 aiohttp 库:
pip install aiohttp
- 异步网络请求示例
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'http://example.com')
print(html[:100]) # 打印前 100 个字符
asyncio.run(main())
在这个例子中,我们使用 aiohttp.ClientSession() 创建一个会话对象,并使用 await session.get(url) 发送异步 GET 请求。然后,我们使用 await response.text() 获取响应的文本内容。
六、总结
async 和 await 是 Python 中处理异步操作的关键字,它们使得编写异步代码变得更加直观和简洁。通过异步编程,我们可以更有效地利用系统资源,提高程序的性能。本文介绍了 async 和 await 的基本概念、用法以及异步编程中的常见模式,并通过实战案例展示了如何使用它们进行异步网络请求。希望这些内容能帮助你更好地理解和使用 Python 中的异步操作。