在Python中处理异步Web请求,核心是利用asyncio构建事件循环,并使用支持异步的HTTP客户端(如aiohttp)来发起非阻塞的网络调用。这种方式可以让程序在等待响应时去执行其他任务,从而提升吞吐量和响应速度。

为什么需要异步Web请求
传统的同步请求库(例如requests)在发送请求后会一直等待服务器返回,期间线程被占用,无法处理其他工作。当并发量较大时,大量线程阻塞会导致资源浪费和延迟升高。异步请求通过单线程内的协程切换,用更少资源支撑更高并发。
- 减少线程切换开销
- 提高IO密集型任务效率
- 代码逻辑清晰,易于维护
使用asyncio与aiohttp基础示例
下面展示一个最简单的异步请求示例,使用aiohttp发送GET请求并读取内容。
import asyncio
import aiohttp
async def fetch(url):
# 创建异步会话
async with aiohttp.ClientSession() as session:
# 发起异步GET请求
async with session.get(url) as resp:
# 等待并读取响应文本
return await resp.text()
async def main():
html = await fetch('https://ipipp.com/index.html')
print(len(html))
# 运行事件循环
asyncio.run(main())
并发控制与错误处理
实际项目中往往需要同时请求多个地址,并且要限制并发数、处理异常。可以使用asyncio.gather配合信号量,或者直接用aiohttp的TCPConnector限制连接数。
import asyncio
import aiohttp
async def fetch(session, url):
try:
async with session.get(url) as resp:
resp.raise_for_status()
return await resp.text()
except Exception as e:
# 返回错误信息而不是中断整个任务
return f'error: {e}'
async def main():
urls = [
'https://ipipp.com/a',
'https://ipipp.com/b',
'https://192.168.0.1/',
]
# 限制最大并发连接为2
connector = aiohttp.TCPConnector(limit=2)
async with aiohttp.ClientSession(connector=connector) as session:
tasks = [fetch(session, u) for u in urls]
results = await asyncio.gather(*tasks)
for r in results:
print(r[:50])
asyncio.run(main())
常见注意事项
- 不要在异步函数内调用阻塞式IO(如time.sleep),应使用await asyncio.sleep()
- 使用
async with确保会话和响应正确关闭 - 对于需要携带参数的请求,使用params字典而非拼接字符串
与同步代码整合
如果老项目基于同步框架,可以通过asyncio.run或在线程中运行事件循环来逐步迁移,不必一次性重写所有逻辑。
异步不是银弹,它主要解决IO等待问题;CPU密集型任务仍应考虑多进程。
| 方式 | 适用场景 | 并发模型 |
|---|---|---|
| requests | 简单脚本、低并发 | 多线程/同步 |
| aiohttp | 高并发爬虫、API网关 | 协程/异步 |
小结
Python处理异步Web请求依赖asyncio事件循环与aiohttp等异步客户端。掌握await语法、并发限制和异常捕获,就能写出高效稳定的网络程序。