如何在FastAPI多Worker场景下共享大内存缓存?
可行解决方案
1. 启用Gunicorn预加载模式(推荐,改动最小)
直接给Gunicorn添加--preload参数启动服务,命令示例:
gunicorn --workers 4 --preload main:app
核心逻辑是Gunicorn会在fork子Worker进程前加载应用及8GB数据。由于你的数据是只读的,Linux写时复制(Copy-On-Write)机制会让所有Worker共享同一份内存页,不会重复占用内存。这样4个Worker仅需8GB内存,同时能利用多CPU核心提升请求处理能力。
注意:若后续业务会修改内存中的数据,会触发写时复制导致内存占用上升,但你的场景是只读数据,完全适配。
2. 单Worker+多线程模式
如果预加载模式存在兼容性问题(比如部分第三方库不支持进程fork),可采用单Worker配合多线程的方式:
gunicorn --workers 1 --threads 4 main:app
单个进程内的多线程会共享内存数据,内存占用仍为8GB。虽然Python的GIL会限制纯Python代码的并行性,但如果你的第三方库是C实现的(多数数据处理类库都是),计算时会主动释放GIL,此时多线程可实现真正的并行处理,有效提升QPS。
3. 进程间共享内存映射
若预加载模式不适用,可通过内存映射(mmap)将大文件直接映射到内存,让所有Worker共享该映射:
import mmap # 应用启动时完成文件映射 with open("large_data_file.bin", "rb") as f: # 映射整个文件到内存,所有进程共享此映射 mapped_data = mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) # 让第三方库从mapped_data读取数据(多数支持类文件对象的库均可直接适配)
这种方式下内存仅保留一份文件映射,所有Worker无需重复加载数据。只要第三方库支持从类文件对象读取数据,几乎无需修改库的内部逻辑,仅需调整数据加载入口即可。
4. 异步Worker+线程池处理CPU任务
若你的端点可改为异步接口,可使用Uvicorn异步Worker配合线程池处理CPU密集任务:
from fastapi import FastAPI import asyncio from concurrent.futures import ThreadPoolExecutor app = FastAPI() # 根据CPU核心数设置线程池大小 executor = ThreadPoolExecutor(max_workers=4) # 单进程加载共享的8GB数据,所有线程共享 large_data = load_data_with_third_party_lib() @app.get("/cpu-intensive") async def cpu_intensive_task(): # 将同步CPU任务提交到线程池执行 result = await asyncio.get_event_loop().run_in_executor( executor, process_data, large_data ) return {"result": result}
启动命令使用异步Worker:
gunicorn --workers 2 --worker-class uvicorn.workers.UvicornWorker main:app
若配合--preload参数,多个Worker仍可共享一份内存数据,进一步优化内存占用。
内容的提问来源于stack exchange,提问作者Oleksandr Havrylchyk
相关产品推荐
相关产品推荐

