Python 现代开发学习笔记

(十九)用异步客户端完成真实网络等待

1. 在一个客户端范围内复用连接

HTTPX 提供异步 HTTP 接口,AsyncClient 管理连接与请求。一个客户端供一批请求共同使用,结束时再关闭:

# 项目文件:demos/httpx_async.py
# get 的网络等待交给事件循环;响应读完后 json() 是普通解析调用,不需要 await。
import asyncio

import httpx
from labserver import running_server


async def read_all(base_url):
    async with httpx.AsyncClient(
        base_url=base_url, timeout=1, trust_env=False
    ) as client:
        async with asyncio.TaskGroup() as group:
            tasks = [
                group.create_task(
                    client.get(f"/api/books/{number}", params={"delay": 0.02})
                )
                for number in [1, 2, 3]
            ]
        records = []
        for task in tasks:
            response = task.result()
            response.raise_for_status()
            records.append(response.json())
    return [record["title"] for record in records]


if __name__ == "__main__":
    with running_server() as server:
        print(asyncio.run(read_all(server.base_url)))

输出三本书名,按任务列表的输入次序排列。base_url 保存共同的地址前缀,params 编码查询,timeout 设置网络等待,trust_env=False 让本机练习直接连接目标,不读取代理等环境配置。异步客户端用 async with 关闭连接池。

await client.get 等待请求与正文读取;response.json() 继续执行同步 JSON 解析。raise_for_status() 把错误状态转换成 HTTPX 的 HTTPStatusError。它要放在希望失败被处理的位置:上例在请求组完成后逐项检查,后面的完整项目会在每个任务里检查,让失败立即传回任务组。HTTPX 异步支持

同一个AsyncClient管理连接,三个任务在网络等待处让出机会,结果按输入排列

2. 把连接限制与操作限制分开

客户端连接池的 Limits(max_connections=2) 限制连接数量;信号量可以覆盖完整的一段“请求、读取、解析”等操作。工作任务拿到信号量后,仍可能等待可用连接,它们控制的资源不是同一个概念。HTTPX 连接限制

HTTPX 的超时分别观察 connect、read、write、pool 等等待:连接、接收下一批数据、发送数据,以及等待池中连接。它们不等于整批任务的总时长;外层再用 asyncio.timeout 安排总预算。HTTPX 超时

请求错误在 RequestError 类别下,例如连接失败、读取超时;错误状态由 raise_for_status 形成 HTTPStatusError;正文 JSON 与书籍字段又是之后的解析与校验。第六章按失败动作保留信息的方法在这里继续使用。HTTPX 错误类别

笔记正文与全部题解 · Ctrl / ⌘ K