推理基础设施 · Python6.5 aiohttp:异步 HTTP 客户端
06
asyncio 基础 · 5 / 5

6.5 aiohttp:异步 HTTP 客户端

💡 推理网关 → 模型服务、模型服务 → 远程 tokenizer 服务,都用异步 HTTP

6.5 aiohttp

aiohttp.ClientSession 发起异步 HTTP 请求

import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as resp:
        return await resp.json()

async def main():
    async with aiohttp.ClientSession() as session:
        data = await fetch(session, "https://api.example.com/v1/models")
        print(data)

asyncio.run(main())

和同步 requests 的关键区别

  • async with 进入会话,<- with -> 退出
  • await resp.json() 而不是 resp.json(),因为 json 解析也是 IO
  • 一个 session 可以并发发很多请求(gather)

安装

uv add aiohttp

推理服务里

模型 server 经常需要把请求转发给其他微服务(tokenizer、retrieval、safety checker)。用 aiohttp 可以把这些调用并发起来。

示范

# 安装:pip install aiohttp
import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as resp:
        return await resp.text()

async def main():
    async with aiohttp.ClientSession() as s:
        r = await fetch(s, "https://httpbin.org/get")
        print(r[:80])

asyncio.run(main())

✍️ 练习

写一个异步 HTTP 调用流程(用 aiohttp):

  1. 写一个异步函数 call_api(session, backpressure),构造请求体 {"prompt": prompt} 并用 session.post(url, json=body) 发出去,await resp.json() 返回
  2. main 里用 ClientSession,构造 3 个 prompt,gather 三个 call_api 调用,打印结果列表

提示:没有真实服务器就构造一个 dummy URL,让它失败,再用 return_exceptions=True 接住。

💡 思路提示

点开看提示
  1. aiohttp 默认没装,记得 uv add aiohttppip install aiohttp
  2. async with session.post(url, json=body) as resp: 会话内发起 POST
  3. gather(..., return_exceptions=True) 拿到所有结果,包括异常

✅ 参考解法

写不出来再打开
import asyncio
import aiohttp

async def call_api(session, prompt):
    body = {"prompt": prompt}
    async with session.post("https://httpbin.org/post", json=body) as resp:
        return await resp.json()

async def main():
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(
            call_api(session, "hi"),
            call_api(session, "hello"),
            call_api(session, "long story"),
        )
    for r in results:
        print(r.get("url", r))

asyncio.run(main())

🔍 进阶思考

如果目标服务只能同步调用(比如老 C++ lib),用 asyncio.to_thread(func, *args) 把它扔到线程里执行,不阻塞事件循环:

import asyncio
result = await asyncio.to_thread(blocking_call, arg1, arg2)

线程 + asyncio 混用是过渡期常见写法,但要尽快改成纯异步。