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

multiprocessing=True时Flask-Cache多GET请求内存占用问题

场景说明

设想如下Flask服务场景,采用SimpleCache作为缓存后端:

from flask.ext.cache import Cache

# 省略Cache实例初始化、Flask app实例初始化逻辑
@cache.memoize
def my_cached_func():
    x = load_some_big_csv()
    return x
    

@app.route('')
def index():
    get_maybe_cached = my_cached_func()
    return get_maybe_cached
问题解答

问题A答复

首先先纠正一个认知偏差:CPU核心是计算调度资源,不存在和服务进程的固定绑定关系,操作系统会随时把进程调度到任意空闲核心上运行,缓存的隔离边界是操作系统进程,和CPU核心没有直接绑定关系。
回到SimpleCache的特性:它是纯进程内的内存缓存,缓存数据直接存在当前Python进程的私有内存字典中,没有任何跨进程共享、同步的机制。基于这个特性可以对应回答你的几个疑问:

  • 当请求被某个worker进程处理时,触发的缓存填充只会写入当前处理请求的worker进程的私有内存,其他独立启动的worker进程完全无法访问这份缓存,这是操作系统进程内存隔离的基本特性决定的。
  • 你提到的“缓存仅存储在单个进程中”的判断是正确的,但这个边界是进程而非CPU核心。
  • 如果你用生产环境最常见的多worker模式部署Flask(比如gunicorn、uWSGI配置的worker数和CPU核心数匹配,通常是12~24个worker配16核CPU),当多个请求被分发到不同worker处理时,每个worker第一次接到请求都会独立执行一次load_some_big_csv(),在自己的内存空间生成一份独立的缓存副本。极端情况下如果16个请求刚好分散到16个不同的worker,内存里确实会存在16份相同的缓存值。

例外情况:如果你用单进程多线程模式部署Flask,所有请求都在同一个进程内处理,不管被调度到哪个CPU核心运行,都会共享同一份SimpleCache,不会生成多份缓存副本。但这种模式因为Python GIL的限制无法充分利用多核性能,且单进程崩溃会直接导致服务不可用,生产环境极少使用。

问题B答复

Python中函数返回自定义对象、容器对象时,默认返回的是对象的内存引用(也就是你说的内存指针),不会主动对对象做拷贝复制。
在同一个worker进程内,10个近并发请求调用my_cached_func()拿到的都是缓存中存储的同一个对象的引用,不会额外复制10份对象占用内存,不存在“内存消耗是单缓存值10倍”的情况。
需要注意两个细节:

  • 这个结论的前提是使用默认配置的SimpleCache:它不会对存入的对象做序列化、深拷贝,直接存原始对象引用。如果你自定义了缓存的序列化逻辑(比如转成pickle字节存储),那取缓存时会反序列化生成新对象,会产生额外内存开销。
  • Flask在构造HTTP响应时,会把返回值序列化成符合HTTP协议的字节流,这个过程会产生临时的内存开销,但这部分内存在响应发送完成后会被GC回收,不属于缓存值的常驻内存占用,也不会留存10份缓存副本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:45:41