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

为什么aiohttp异步请求代码运行时表现为同步状态?

问题原因及修复方案

1. 替换阻塞同步调用

你用time.sleep()测试时表现为同步是核心的常识性错误:time.sleep()是阻塞同步函数,调用时会直接卡住整个asyncio事件循环,不会释放执行权给其他协程,自然所有任务都是串行执行的。要模拟异步等待场景必须使用异步等待函数asyncio.sleep()。
同理,所有async函数内都不能直接调用同步IO逻辑(比如普通文件读写、同步HTTP请求、CPU密集计算等),要么替换为对应异步库实现,要么将同步逻辑扔到线程/进程池中执行。

2. 高并发场景的限制问题

你原代码一次性将数十万行对应的协程任务全部提交给asyncio.gather()执行,会触发两层瓶颈,导致看起来接近同步执行:

  • aiohttp的ClientSession默认有连接池限制,默认最大并发连接数为100,超出的请求会排队等待空闲连接,不会真的并发发送
  • 你的本地API服务端本身也有并发承载上限,同一时间只能处理有限个请求,多余请求会在服务端队列等待,客户端视角看就是串行返回

3. 修复后的代码示例

import asyncio
import aiohttp
import sys

# 调整并发数为你本地API可承载的最大值,建议从100~500逐步测试调整
MAX_CONCURRENT = 200
semaphore = asyncio.Semaphore(MAX_CONCURRENT)

async def process_line_async(session, line):
    async with semaphore: # 用信号量限制并发数
        async with session.put('http://localhost:8887/load', data=line) as response:
            r = await response.json()
            sys.stdout.write(f"some info about the response\n")
        # 测试时用下面的异步sleep替换请求逻辑
        # await asyncio.sleep(1)
        # print(line)

async def looper(lines):
    async with aiohttp.ClientSession(
        # 手动调大连接池上限,和MAX_CONCURRENT对齐即可
        connector=aiohttp.TCPConnector(limit=MAX_CONCURRENT)
    ) as session:
        tasks = []
        for line in lines:
            task = asyncio.ensure_future(process_line_async(session, line))
            tasks.append(task)
        await asyncio.gather(*tasks)

# 假设你的main函数是调用looper
async def main(lines):
    await looper(lines)

# asyncio.run(main(lines))

额外优化建议

如果数据量达到数十万级别,不建议一次性创建所有任务存到列表,会占用大量内存,可以按批次处理:每批创建200个任务,跑完一批再创建下一批,内存占用会低很多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:48:00