You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用aiohttp进行异步调用无法扩展的性能问题求助

优化aiohttp异步请求吞吐量的方案

看起来你的aiohttp异步请求遇到了明显的性能瓶颈啊,结合你给出的性能分析数据和场景,我来帮你拆解问题并给出针对性的优化建议:

问题核心分析

你的服务端是立即响应的,RTT仅7ms,理论上2000个异步请求应该在几毫秒内完成,但实际耗时超2秒,性能分析里poll调用占了0.9秒——这说明默认的事件循环IO多路复用机制效率不足,再加上可能的连接池限制,导致请求排队、IO等待耗时被放大。

具体优化步骤

1. 替换为更高效的事件循环后端

Python默认的select selector在高并发场景下性能很差,换成uvloop(基于libuv的高性能事件循环)能大幅降低poll调用的耗时:

  • 先安装依赖:
    pip install uvloop
    
  • 在代码开头替换事件循环策略:
    import asyncio
    import uvloop
    
    # 全局替换为uvloop
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    

uvloop会自动使用系统最优的多路复用机制(Linux下是epoll,macOS是kqueue),比默认实现快数倍,能直接减少IO等待的开销。

2. 调整aiohttp连接池参数

aiohttp默认的TCPConnector连接池大小(limit)是100,limit_per_host也是100——这意味着你发起2000个请求时,大部分请求会排队等待可用连接,直接拉长了总耗时。

  • 创建ClientSession时调大连接池限制:
    from aiohttp import ClientSession, TCPConnector
    
    # 根据需求设置合适的连接数,2000的话可以直接设为对应值
    connector = TCPConnector(limit=2000, limit_per_host=2000)
    async with ClientSession(connector=connector) as session:
        # 你的请求逻辑
        tasks = [asyncio.create_task(session.get("http://your-server")) for _ in range(2000)]
        await asyncio.gather(*tasks)
    

注意:不要设置过大导致系统端口耗尽,2000的量级在大多数系统下是安全的。

3. 优化任务调度方式

确保请求任务是被正确异步调度的:

  • 使用asyncio.create_task提前创建任务,而不是直接将协程对象传入asyncio.gather,这样事件循环能更早地调度任务执行,减少启动延迟。

4. 系统层面的辅助优化

  • 调大文件描述符限制:Python进程默认的文件描述符限制可能不足以支撑2000个并发连接,临时调整:
    ulimit -n 65535
    
  • 优化TCP参数:减少TIME_WAIT状态的连接占用端口,提升连接复用效率:
    sysctl -w net.ipv4.tcp_tw_reuse=1
    sysctl -w net.ipv4.tcp_fin_timeout=30
    

预期效果

做完这些优化后,2000个请求的总耗时应该会接近RTT的7ms左右,吞吐量也能突破当前1000req/s的限制,达到更理想的水平。

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

火山引擎 最新活动