Python并发请求实现_asyncio网络实战

11次阅读

Python 并发请求实现_asyncio 网络实战

asyncio并发请求 的核心逻辑

Python 中用 asyncio 发并发 HTTP 请求,关键不是“同时发 100 个”,而是让 IO 等待时不阻塞主线程——比如发请求后不等响应,立刻切去处理下一个请求或已返回的数据。真正起效的前提是:所有 IO 操作(如 HTTP 请求)都得是异步的,不能混用 requests 这类同步库。

用 aiohttp 替代 requests 发异步请求

aiohttpasyncio 生态中最常用的异步 HTTP 客户端。它本身基于 async/await 设计,能自然融入事件循环。安装后直接用 session.get() 发起请求,配合 async with 管理连接生命周期,避免资源泄漏。

  • 创建 aiohttp.ClientSession() 一次,复用给多个请求,别每次新建
  • 每个请求用await session.get(url),不是session.get(url).text()
  • 响应体用 await resp.text()await resp.json(),加await
  • timeout 参数防卡死,例如timeout=aiohttp.ClientTimeout(total=10)

控制并发数防止目标服务器压力过大

无限制并发(如 asyncio.gather(*tasks) 扔几百个任务)可能触发对方限流、封 IP,或耗尽本地文件描述符。推荐用 asyncio.Semaphore 做并发限流:

  • 初始化一个信号量:sem = asyncio.Semaphore(10),表示最多 10 个并发
  • 每个请求前async with sem:,自动排队获取许可
  • 结合 asyncio.create_task() 启动任务,比 gather 更灵活,便于错误隔离和重试

异常处理与重试不能省略

网络请求失败很常见:超时、连接拒绝、状态码非 2xx、JSON 解析失败……这些在异步里不会自动中断整个程序,但若不捕获,错误会被静默吞掉或导致后续逻辑出错。

立即学习Python 免费学习笔记(深入)”;

  • 每个 await session.get() 外层套try/except aiohttp.ClientError
  • 检查resp.status,非 2xx 时主动raise Exception(f"HTTP {resp.status}")
  • 重试建议用 tenacity 库(支持 async),或手写带指数退避的async def fetch_with_retry()
  • 记录失败 URL 和原因,方便事后排查,别只打印然后跳过

完整最小可运行示例

以下代码实现 10 个并发请求,每秒最多 5 个,带基础错误处理:

import asyncio import aiohttp <p>async def fetch(session, url, sem): async with sem: try: async with session.get(url, timeout=5) as resp: if resp.status == 200: return await resp.text() else: raise Exception(f"HTTP {resp.status}") except Exception as e: return f"ERROR: {url} → {e}"</p><p>async def main(): urls = ["<a href="https://www.php.cn/link/5f69e19efaba426d62faeab93c308f5c">https://www.php.cn/link/5f69e19efaba426d62faeab93c308f5c</a>"] <em> 20 sem = asyncio.Semaphore(5) async with aiohttp.ClientSession() as session: tasks = [fetch(session, url, sem) for url in urls] results = await asyncio.gather(</em>tasks, return_exceptions=True) print(f" 完成 {len(results)} 个请求 ")</p><p>asyncio.run(main())</p>

text=ZqhQzanResources