FastAPI中Python Swift客户端异步上传OpenStack对象存储的问题求解
解决方案:异步上传至OpenStack Swift
问题根源
你的代码里swift_connection.put_object()是同步阻塞方法,在异步函数中调用时会卡住整个asyncio事件循环,导致asyncio.gather()无法真正并行执行任务,反而因为异步调度的额外开销比纯同步代码更慢。从日志也能看出来,上传任务是顺序执行的,没有并行。
可行方案
1. 用线程池包装同步上传操作
把阻塞的put_object()放到线程池中执行,避免阻塞事件循环,让多个上传任务可以并行处理。Python 3.9+可以用asyncio.to_thread(),更低版本用loop.run_in_executor()。
修改后的代码示例:
import asyncio import time from io import BytesIO from PIL import Image from fastapi import FastAPI # 省略认证代码 # [...] app = FastAPI() async def async_upload_image(idx, img): print("Start upload image:{}".format(idx)) # 图片转字节(若这步耗时,同样可放到线程池) data = BytesIO() img.save(data, format='png') data = data.getvalue() # 将同步上传操作委托给线程池 await asyncio.to_thread( swift_connection.put_object, 'dev', img['path'], # 原代码写的是image['path'],这里修正为img data ) print("Finish upload image:{}".format(idx)) return True @app.get("/test-async") async def test_async(): image = Image.open('./sketch-mountains-input.jpg') images = [image, image, image, image ] start = time.time() futures = [async_upload_image(idx, img) for idx, img in enumerate(images)] await asyncio.gather(*futures) end = time.time() print('It took {} seconds to finish execution'.format(round(end-start))) return True
修改后,多个上传任务会在不同线程并行执行,事件循环不会被阻塞,速度会远快于原来的伪异步实现,甚至超过纯同步执行效率。
2. 使用原生异步的OpenStack客户端
如果项目允许更换依赖,可选择支持异步的OpenStack Swift客户端库,比如openstacksdk的异步分支或专门的异步Swift客户端。这类库的put_object是原生异步方法,无需额外包装就能在asyncio环境下高效并行执行。
3. 批量上传优化(可选)
若上传文件数量较多,可考虑使用Swift的批量上传API(如bulk_upload),合并多个上传请求,减少HTTP连接开销,进一步提升整体效率。
内容的提问来源于stack exchange,提问作者Alexis.Rolland
相关产品推荐
相关产品推荐

