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
相关产品推荐
相关产品推荐

