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

asyncio.gather是否真的不并行?FastAPI S3上传测试疑问

asyncio.gather()在FastAPI多文件S3上传中的并行性问题

我正在探究asyncio.gather()的并行性,在FastAPI应用中需同时上传4个文件至S3,当前使用本地S3测试(延迟极低),但测试结果令我困惑。我对三种实现方案各执行5次,以下是各方案的最快执行结果:

方案1:Asyncio Gather结合Partial

loop = asyncio.get_running_loop()
start = time.time() * 1000
await asyncio.gather(
    *[
        loop.run_in_executor(
            None,
            functools.partial(
                s3_client.upload_fileobj, file.file, "test", file.filename
            ),
        )
        for file in files
    ]
)
end = time.time() * 1000
print(f"gather time: {end - start}")

执行耗时(5次测试):125ms、130ms、119ms、122ms、132ms

方案2:Asyncio Gather结合Tasks与独立异步函数

async def s3_upload_fileobj_async(*args, **kwargs):
    return s3_client.upload_fileobj(*args, **kwargs)

start = time.time() * 1000
await asyncio.gather(
    *[
        asyncio.create_task(
            s3_upload_fileobj_async(file.file, "test", file.filename)
        )
        for file in files
    ]
)
end = time.time() * 1000
print(f"gather time: {end - start}")

执行耗时(5次测试):194ms、163ms、152ms、168ms、164ms

方案3:普通同步函数

start_total = time.time() * 1000
for file in files:
    start = time.time() * 1000
    s3_client.upload_fileobj(file.file, "test", file.filename)
    end = time.time() * 1000
    print(f"File: {file.filename} time: {end - start}")

end_total = time.time() * 1000
print(f"Total time: {end_total - start_total}")

单文件上传耗时(首次执行):32.92822265625ms、41.922119140625ms、39.576904296875ms、49.405029296875ms
总执行耗时(5次测试):163ms、222ms、162ms、182ms、156ms

观察结论

  • 结合Tasks的Asyncio Gather与同步代码速度大致相当
  • 结合Partial的Asyncio Gather速度优于所有方案

疑问

单文件最长上传耗时为49ms,若asyncio.gather同时启动所有任务,理论总耗时应等于最长单文件上传耗时,但实际结果为:49ms vs 163ms(Tasks方案)、49ms vs 125ms(Partial方案)。为何结合Tasks的Asyncio Gather性能近乎同步代码?使用asyncio.gather的任务是否未真正并行执行?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:27:21