[python]使用flask-caching缓存数据
简介
Flask-Caching 是 Flask 的一个扩展,为任何 Flask 应用程序添加了对各种后端的缓存支持。它基于 cachelib 运行,并通过统一的 API 支持 werkzeug 的所有原始缓存后端。开发者还可以通过继承 flask_caching.backends.base.BaseCache 类来开发自己的缓存后端。
安装
pip install Flask-Caching
设置
缓存通过缓存实例来管理
from flask import Flask
from flask_caching import Cacheconfig = {"DEBUG": True, # some Flask specific configs"CACHE_TYPE": "SimpleCache", # Flask-Caching related configs"CACHE_DEFAULT_TIMEOUT": 300
}
app = Flask(__name__)
# tell Flask to use the above defined config
app.config.from_mapping(config)
cache = Cache(app)
也可以使用init_app来延后配置缓存实例
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})app = Flask(__name__)
cache.init_app(app)
还可以提供一个备用的配置字典,如果有多个Cache缓存实例,每个实例使用不同的后端,这将非常有用。
#: Method A: During instantiation of class
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
#: Method B: During init_app call
cache.init_app(app, config={'CACHE_TYPE': 'SimpleCache'})
缓存视图函数
使用cached()装饰器缓存视图函数,默认使用path作为缓存的key
@app.route("/")
@cache.cached(timeout=50)
def index():return render_template('index.html')
cached 装饰器还有另一个可选参数叫做 unless。这个参数接受一个可调用对象,它返回 True 或 False。如果 unless 返回 True,那么将完全跳过缓存机制。
为了在视图中动态确定超时时间,可以返回 CachedResponse,这是 flask.Response 的子类。
@app.route("/")
@cache.cached()
def index():return CachedResponse(response=make_response(render_template('index.html')),timeout=50,)
缓存插拔式视图类
from flask.views import Viewclass MyView(View):@cache.cached(timeout=50)def dispatch_request(self):return 'Cached for 50s'
缓存其它函数
使用相同的 @cached 装饰器,还可以缓存其他非视图相关的函数的结果。需要注意替换 key_prefix,否则它将使用 request.path 作为 cache_key。键控制从缓存中获取什么内容。例如,如果一个键在缓存中不存在,将会在缓存中创建一个新的键值对条目。否则,将会返回该键的值(即缓存的结果)。
@cache.cached(timeout=50, key_prefix='all_comments')
def get_all_comments():comments = do_serious_dbio()return [x.author for x in comments]cached_comments = get_all_comments()
自定义缓存键
有时您希望为每个路由定义自己的缓存键。使用 @cached 装饰器,您可以指定如何生成这个键。当缓存键不应仅仅是默认的 key_prefix,而是必须从请求中的其他参数派生时,这可能会非常有用。例如,在缓存 POST 路由时,缓存键应该根据请求中的数据而不仅仅是路由或视图本身来确定,这时就可以使用这个功能。
def make_key():"""A function which is called to derive the key for a computed value.The key in this case is the concat value of all the json requestparameters. Other strategy could to use any hashing function.:returns: unique string for which the value should be cached."""user_data = request.get_json()return ",".join([f"{key}={value}" for key, value in user_data.items()])@app.route("/hello", methods=["POST"])
@cache.cached(timeout=60, make_cache_key=make_key)
def some_func():....
记忆化
在记忆化中,函数参数也会包含在cache_key中
注意:对于不接收参数的函数来说,cached() 和 memoize() 实际上是相同的。
Memoize 也适用于方法,因为它会将 self或 cls 参数的身份作为缓存键的一部分。
记忆化背后的理论是,如果你有一个函数需要在一次请求中多次调用,那么它只会在第一次使用这些参数调用该函数时进行计算。例如,一个 sqlalchemy 对象用来确定一个用户是否具有某个角色。在一次请求中,你可能需要多次调用这个函数。为了避免每次需要这些信息时都访问数据库,你可能会做如下操作:
class Person(db.Model):@cache.memoize(50)def has_membership(self, role_id):return Group.query.filter_by(user=self, role_id=role_id).count() >= 1
将可变对象(类等)作为缓存键的一部分可能会变得棘手。建议不要将对象实例传递给记忆化函数。然而,memoize 会对传入的参数执行 repr(),因此如果对象有一个返回唯一标识字符串的 __repr__ 函数,该字符串将被用作缓存键的一部分。
例如,一个 sqlalchemy 的 person 对象,返回数据库 ID 作为唯一标识符的一部分:
class Person(db.Model):def __repr__(self):return "%s(%s)" % (self.__class__.__name__, self.id)
删除记忆化缓存
您可能需要按函数删除缓存。使用上述示例,假设您更改了用户的权限并将其分配给某个角色,但现在您需要重新计算他们是否拥有某些成员资格。您可以使用 delete_memoized() 函数来实现这一点:
cache.delete_memoized(user_has_membership)
如果仅将函数名称作为参数提供,那么该函数的所有记忆化版本都将失效。然而,您可以通过提供与缓存时相同的参数值来删除特定的缓存。在下面的示例中,只有用户角色的缓存被删除:
user_has_membership('demo', 'admin')
user_has_membership('demo', 'user')cache.delete_memoized(user_has_membership, 'demo', 'user')
如果一个类方法被记忆化,您必须将类作为第一个 *args 参数提供。
class Foobar(object):@classmethod@cache.memoize(5)def big_foo(cls, a, b):return a + b + random.randrange(0, 100000)cache.delete_memoized(Foobar.big_foo, Foobar, 5, 2)
缓存Jinja2模板
基本使用
{% cache [timeout [,[key1, [key2, ...]]]] %}
...
{% endcache %}
默认情况下,“模板文件路径” + “块开始行”的值被用作缓存键。此外,键名也可以手动设置。键会连接成一个字符串,这样可以避免在不同模板中评估相同的块。
将超时设置为 None 以表示没有超时,但可以使用自定义键。
{% cache None, "key" %}
...
{% endcache %}
设置timeout为del来删除缓存值
{% cache 'del', key1 %}
...
{% endcache %}
如果提供了键,您可以轻松生成模板片段的键,并在模板上下文外部删除它。
from flask_caching import make_template_fragment_key
key = make_template_fragment_key("key1", vary_on=["key2", "key3"])
cache.delete(key)
考虑使用render_form_field和render_submit
{% cache 60*5 %}
<div><form>{% render_form_field(form.username) %}{% render_submit() %}</form>
</div>
{% endcache %}
清空缓存
清空应用缓存的简单示例
from flask_caching import Cachefrom yourapp import app, your_cache_configcache = Cache()def main():cache.init_app(app, config=your_cache_config)with app.app_context():cache.clear()if __name__ == '__main__':main()
某些后端实现不支持完全清除缓存。此外,如果您不使用键前缀,一些实现(例如 Redis)会清空整个数据库。请确保您没有在缓存数据库中存储任何其他数据。
显式缓存数据
数据可以通过直接使用代理方法如 Cache.set() 和 Cache.get() 来显式缓存。通过 Cache 类还有许多其他可用的代理方法。
@app.route("/html")
@app.route("/html/<foo>")
def html(foo=None):if foo is not None:cache.set("foo", foo)bar = cache.get("foo")return render_template_string("<html><body>foo cache: {{bar}}</body></html>", bar=bar)
基本使用示例
from flask import Flask
from flask_caching import Cache
import timeflask_cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})app = Flask(__name__)fake_db = {"zhangsan": "qwerty"
}def do_io(username: str):time.sleep(0.01)return fake_db.get(username, "")@app.get("/user/<username>")
def get_user(username):if data := flask_cache.get(username):print(f"getting data from cache, username: {username}")return dataelse:print("data not found in cache")db_data = do_io(username)flask_cache.set(username, db_data, timeout=10)return db_dataif __name__ == "__main__":flask_cache.init_app(app)app.run("127.0.0.1", 8000)
- 测试
wrk -t1 -c10 -d30s http://127.0.0.1:8000/user/zhangsan
SimpleCache在gunicorn中的问题
gunicorn会创建多个子进程,子进程之间是否共享simplecache?
先写一个普通的service,暴露两个api
GET /cache/<key_name>: 根据key name获取缓存值POST /cache: 添加缓存
from flask import Flask, request
from flask_caching import Cache
from typing import Optionalflask_config = {"CACHE_TYPE": "SimpleCache","CACHE_DEFAULT_TIMEOUT": 300
}app = Flask(__name__)
app.config.from_mapping(flask_config)
cache = Cache(app)@app.get("/cache/<foo>")
def get_cached_data(foo: Optional[str]):if not foo:return "foo is None\n"cache_rst = cache.get(foo)if not cache_rst:return f"key {foo} is not in cache\n"return f"find key {foo} in cache, value is {cache_rst}\n"@app.post("/cache")
def set_cached_data():try:req_body = request.get_json()except Exception as e:raise Exception(f"request body is not json format, error: {e}\n") from ekey = req_body.get("key", None)value = req_body.get("value", None)if not key or not value:return "key or value is None\n"if cached_data := cache.get(key):return f"key {key} is already in cache, value is {cached_data}\n"cache.set(key, value)return f"set key {key} in cache, value is {value}\n"if __name__ == "__main__":app.run(host="0.0.0.0", port=5000)
先用flask默认运行方式运行,测试接口是否正常
# 添加键值对缓存
curl -X POST http://127.0.0.1:5000/cache -H 'Content-Type: application/json' -d '{"key": "k1", "value": "v1"}'# 获取缓存
curl http://127.0.0.1:5000/cache/k1
如果响应正常的话,再用gunicorn启动。如下命令将启动4个工作子进程
gunicorn demo:app -b 0.0.0.0:5000 -w 4 -k gevent --worker-connections 2000
请求测试。第一个请求设置缓存,后面四个获取缓存,可见工作进程之间并不共享flask_cache。如果用gunicorn或多个flask service实例,最好换其他cache type,比如RedisCache。
$ curl -X POST http://127.0.0.1:5000/cache -H 'Content-Type: application/json' -d '{"key": "k1", "value": "v1"}'
set key k1 in cache, value is v1$ curl http://127.0.0.1:5000/cache/k1
key k1 is not in cache$ curl http://127.0.0.1:5000/cache/k1
key k1 is not in cache$ curl http://127.0.0.1:5000/cache/k1
find key k1 in cache, value is v1$ curl http://127.0.0.1:5000/cache/k1
key k1 is not in cache
关注灵活就业新业态,关注公账号:贤才宝(贤才宝https://www.51xcbw.com)
相关文章:
[python]使用flask-caching缓存数据
简介 Flask-Caching 是 Flask 的一个扩展,为任何 Flask 应用程序添加了对各种后端的缓存支持。它基于 cachelib 运行,并通过统一的 API 支持 werkzeug 的所有原始缓存后端。开发者还可以通过继承 flask_caching.backends.base.BaseCache 类来开发自己的…...
裸机按键输入实验
一、硬件原理分析 按键就两个状态:按下或弹起,将按键连接到一个 IO 上,通过读取这个 IO 的值就知道按 键是按下的还是弹起的。至于按键按下的时候是高电平还是低电平要根据实际电路来判断。前 面几章我们都是讲解 I.MX6U 的 GPIO 作为输出使用…...
GaussDB运维管理工具(二)
GaussDB运维管理工具(二) 集群管理组件cm_ctl工具介绍cm_ctl工具使用查询集群状态启停集群主备切换重建备DN检测进程运行查看实例配置文件手动剔除故障CNCM参数获取和配置停止仲裁 Cluster Manager(缩写为CM)是GaussDB的集群管理工…...
【HarmonyOS之旅】HarmonyOS开发基础知识(一)
目录 1 -> 应用基础知识 1.1 -> 用户应用程序 1.2 -> 用户应用程序包结构 1.3 -> Ability 1.4 -> 库文件 1.5 -> 资源文件 1.6 -> 配置文件 1.7 -> pack.info 1.8 -> HAR 2 -> 配置文件简介 2.1 -> 配置文件的组成 3 -> 配置文…...
Mysql数据究竟是如何存储的
Mysql行列式 开篇 笔者这几日在学习mysql是这么运行的这本书,感觉书中的内容受益匪浅,想整理成自己的话分享给大家,平时大家工作和生活中可能没有时间去专心投入读取一本书,而mysql是这么运行的这本书需要投入大量的时间的学…...
STM32单片机使用CAN协议进行通信
CAN总线(控制器局域网总线) 理论知识 CAN总线是由BOSCH公司开发的一种简洁易用、传输速度快、易扩展、可靠性高的串行通信总线 CAN总线特征 两根通信线(CAN_H、CAN_L),线路少,无需共地差分信号通信&…...
Docker 入门:如何使用 Docker 容器化 AI 项目(二)
四、将 AI 项目容器化:示例实践 - 完整的图像分类与 API 服务 让我们通过一个更完整的 AI 项目示例,展示如何将 AI 项目容器化。我们以一个基于 TensorFlow 的图像分类模型为例,演示如何将训练、推理、以及 API 服务过程容器化。 4.1 创建 …...
MVVM、MVC、MVP 的区别
MVVM(Model-View-ViewModel)、MVC(Model-View-Controller)和MVP(Model-View-Presenter)是三种常见的软件架构模式,它们在客户端应用开发中被广泛使用。每种模式都有其特定的设计理念和应用场景&…...
【Verilog】期末复习
数字逻辑电路分为哪两类?它们各自的特点是什么? 组合逻辑电路:任意时刻的输出仅仅取决于该时刻的输入,而与电路原来的状态无关 没有记忆功能,只有从输入到输出的通路,没有从输出到输入的回路 时序逻辑电路&…...
C#都可以找哪些工作?
在国内学习C#,可以找的工作主要是以下4个: 1、游戏开发 需要学习C#编程、Unity引擎操作、游戏设计和3D图形处理等。 2、PC桌面应用开发 需要学习C#编程、WinForm框架/WPF框架、MVVM设计模式和UI/UX设计等。 3、Web开发 需要学习C#编程、ASP.NET框架…...
机器学习Python使用scikit-learn工具包详细介绍
一、简介 Scikit-learn是一个开源的机器学习库,用于Python编程语言。它建立在NumPy、SciPy和matplotlib这些科学计算库之上,提供了简单有效的数据挖掘和数据分析工具。Scikit-learn库包含了许多用于分类、回归、聚类和降维的算法,包括支持向量…...
蓝桥杯真题 - 扫雷 - 题解
题目链接:https://www.lanqiao.cn/problems/549/learning/ 个人评价:难度 1 星(满星:5) 前置知识:无 整体思路 按题意模拟;为了减少不必要的“数组越界”判断,让数组下标从 1 1 1…...
vue3项目结合Echarts实现甘特图(可拖拽、选中等操作)
效果图: 图一:选中操作 图二:上下左右拖拽操作 本案例在echarts示例机场航班甘特图的基础上修改 封装ganttEcharts组件,测试数据 airport-schedule.jsonganttEcharts代码: 直接复制粘贴可测…...
Log4j2 插件的简单使用
代码: TestPlugin.java package com.chenjiacheng.webapp.plugins;import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.lookup.StrLookup;/*** Created by chenjiacheng on …...
Linux之RPM和YUM命令
一、RPM命令 1、介绍 RPM(RedHat Package Manager).,RedHat软件包管理工具,类似windows里面的setup,exe是Liux这系列操作系统里而的打包安装工具。 RPMI包的名称格式: Apache-1.3.23-11.i386.rpm “apache’” 软件名称“1.3.23-11” 软件的版本号&am…...
读取硬件板子上的数据
SSCOM工具,先要安装一个插件 这样就可以读到设备数据...
Cesium 实例化潜入潜出
Cesium 实例化潜入潜出 1、WebGL Instance 的原理 狭义的的WebGL 中说使用 Instance, 一般指使用 glDrawArraysInstanced 用于实例化渲染的函数。它允许在一次绘制调用中渲染多个相同的几何体实例,而无需为每个实例发起单独的绘制调用。 Three.js 就是使用这种方…...
java引入jedis并且关于开放redis端口问题
博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:数据库 JavaEE专栏:JavaEE 软件测试专栏:软件测试 关注博主带你了解更多知识 目录 1. 引入jedis 编辑 2. 关于java客户端开放redis端口问题 3. 连接redis服务器 redis服务器在官网公开了使用的协议: resp…...
【人工智能】用Python实现情感分析:从简单词典到深度学习方法的演进
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 情感分析是自然语言处理(NLP)中的一个重要任务,其目的是通过分析文本内容,识别出其中的情感极性,如正面、负面或中性。随着技术的不断…...
关系型数据库的完整性和一致性
完整性 1.实体完整性 - 每一个实体都是独一无二的,没有冗余 --主键/唯一索引 2.参照完整性 - 外键 3.域完整性 - 存储的数据都是有效的数据 --数据类型/数据长度/非空约束/检查约束/ 检查约束: alter table tb_score add constraint ck_score_scmar…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
