You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI高并发场景下httpx性能劣于aiohttp的原因及代码排查请求

FastAPI同步异步路由测试:httpx复用实例性能低于aiohttp问题排查

在FastAPI框架中进行同步与异步路由测试时,发现复用同一客户端实例的httpx在高并发请求场景下性能远不如aiohttp,现针对代码问题排查如下:

原测试代码

import uvicorn
from fastapi import FastAPI
import requests
import httpx
import aiohttp

app = FastAPI(description="sync and async route func test")

aio_client = httpx.AsyncClient()
aio_session: aiohttp.ClientSession = None
req_session = requests.Session()


@app.on_event("startup")
async def startup_event():
    global aio_session
    aio_session = aiohttp.ClientSession()


async def async_get(url):
    # async with aio_session.get(url) as resp:
    #     return resp

    resp = await aio_client.get(url)
    return resp


@app.get("/ping")
async def ping():
    return "pong"


@app.get("/async_route_func_demo")
async def async_route_func():
    url = "https://juejin.cn/"
    resp = await async_get(url)
    # print("resp", resp)
    return "async_route_func_demo"


@app.get("/async_route_use_sync_io_demo")
async def async_route_func():
    url = "https://juejin.cn/"
    resp = req_session.get(url)
    # print("resp", resp)
    return "async_route_func_demo"


@app.get("/sync_route_func_demo")
def sync_route_func():
    url = "https://juejin.cn/"
    resp = req_session.get(url)
    # print("resp", resp)
    return "sync_route_func_demo"


def main():
    uvicorn.run(app, log_level="warning")


if __name__ == '__main__':
    main()

环境信息

  • Python版本:3.10.12
  • 操作系统:macOS M1 Pro
  • 依赖版本:
fastapi==0.101.0
uvicorn==0.23.2
requests==2.32.0
httpx==0.27.0

wrk测试结果

高并发测试显示,使用复用httpx异步客户端实例的路由接口,QPS、延迟等核心性能指标均显著落后于使用aiohttp客户端的版本。

问题排查与修正

原代码核心问题

  1. httpx客户端初始化时机错误:在模块级别直接创建httpx.AsyncClient(),未在FastAPI的异步启动上下文内完成初始化,导致客户端与事件循环绑定异常,高并发场景下易出现资源竞争或阻塞。
  2. 未正确销毁httpx客户端:仅在启动事件中初始化了aiohttp会话,但未在服务关闭时关闭httpx客户端,会引发连接池资源泄漏,长期运行后性能持续下降。
  3. 对比测试逻辑未启用:原代码中aiohttp的调用逻辑被注释,无法直接完成两者的性能对比验证。

修正后的代码

import uvicorn
from fastapi import FastAPI
import requests
import httpx
import aiohttp

app = FastAPI(description="sync and async route func test")

aio_client: httpx.AsyncClient = None
aio_session: aiohttp.ClientSession = None
req_session = requests.Session()


@app.on_event("startup")
async def startup_event():
    global aio_session, aio_client
    # 在异步启动上下文内初始化客户端,确保与事件循环正确绑定
    aio_session = aiohttp.ClientSession()
    # 对齐aiohttp默认连接池配置,缩小性能差异
    aio_client = httpx.AsyncClient(
        limits=httpx.Limits(max_keepalive_connections=100, max_connections=200)
    )


@app.on_event("shutdown")
async def shutdown_event():
    # 关闭所有客户端,释放资源
    await aio_session.close()
    await aio_client.aclose()
    req_session.close()


async def async_get_httpx(url):
    resp = await aio_client.get(url)
    return resp


async def async_get_aiohttp(url):
    async with aio_session.get(url) as resp:
        return resp


@app.get("/ping")
async def ping():
    return "pong"


@app.get("/async_route_httpx")
async def async_route_httpx():
    url = "https://juejin.cn/"
    await async_get_httpx(url)
    return "async_route_httpx"


@app.get("/async_route_aiohttp")
async def async_route_aiohttp():
    url = "https://juejin.cn/"
    await async_get_aiohttp(url)
    return "async_route_aiohttp"


@app.get("/async_route_use_sync_io")
async def async_route_use_sync_io():
    url = "https://juejin.cn/"
    resp = req_session.get(url)
    return "async_route_use_sync_io"


@app.get("/sync_route_func")
def sync_route_func():
    url = "https://juejin.cn/"
    resp = req_session.get(url)
    return "sync_route_func"


def main():
    uvicorn.run(app, log_level="warning")


if __name__ == '__main__':
    main()

额外说明

httpx默认连接池配置与aiohttp存在差异,初始化时显式设置limits参数对齐两者的连接池大小,可进一步缩小性能差距。

内容的提问来源于stack exchange,提问作者hui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 11:30:54