当前位置: 首页 > news >正文

[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 %}

设置timeoutdel来删除缓存值

{% 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_fieldrender_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 的一个扩展&#xff0c;为任何 Flask 应用程序添加了对各种后端的缓存支持。它基于 cachelib 运行&#xff0c;并通过统一的 API 支持 werkzeug 的所有原始缓存后端。开发者还可以通过继承 flask_caching.backends.base.BaseCache 类来开发自己的…...

裸机按键输入实验

一、硬件原理分析 按键就两个状态&#xff1a;按下或弹起&#xff0c;将按键连接到一个 IO 上&#xff0c;通过读取这个 IO 的值就知道按 键是按下的还是弹起的。至于按键按下的时候是高电平还是低电平要根据实际电路来判断。前 面几章我们都是讲解 I.MX6U 的 GPIO 作为输出使用…...

GaussDB运维管理工具(二)

GaussDB运维管理工具&#xff08;二&#xff09; 集群管理组件cm_ctl工具介绍cm_ctl工具使用查询集群状态启停集群主备切换重建备DN检测进程运行查看实例配置文件手动剔除故障CNCM参数获取和配置停止仲裁 Cluster Manager&#xff08;缩写为CM&#xff09;是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是这么运行的这本书&#xff0c;感觉书中的内容受益匪浅&#xff0c;想整理成自己的话分享给大家&#xff0c;平时大家工作和生活中可能没有时间去专心投入读取一本书&#xff0c;而mysql是这么运行的这本书需要投入大量的时间的学…...

STM32单片机使用CAN协议进行通信

CAN总线&#xff08;控制器局域网总线&#xff09; 理论知识 CAN总线是由BOSCH公司开发的一种简洁易用、传输速度快、易扩展、可靠性高的串行通信总线 CAN总线特征 两根通信线&#xff08;CAN_H、CAN_L&#xff09;&#xff0c;线路少&#xff0c;无需共地差分信号通信&…...

Docker 入门:如何使用 Docker 容器化 AI 项目(二)

四、将 AI 项目容器化&#xff1a;示例实践 - 完整的图像分类与 API 服务 让我们通过一个更完整的 AI 项目示例&#xff0c;展示如何将 AI 项目容器化。我们以一个基于 TensorFlow 的图像分类模型为例&#xff0c;演示如何将训练、推理、以及 API 服务过程容器化。 4.1 创建 …...

MVVM、MVC、MVP 的区别

MVVM&#xff08;Model-View-ViewModel&#xff09;、MVC&#xff08;Model-View-Controller&#xff09;和MVP&#xff08;Model-View-Presenter&#xff09;是三种常见的软件架构模式&#xff0c;它们在客户端应用开发中被广泛使用。每种模式都有其特定的设计理念和应用场景&…...

【Verilog】期末复习

数字逻辑电路分为哪两类&#xff1f;它们各自的特点是什么&#xff1f; 组合逻辑电路&#xff1a;任意时刻的输出仅仅取决于该时刻的输入&#xff0c;而与电路原来的状态无关 没有记忆功能&#xff0c;只有从输入到输出的通路&#xff0c;没有从输出到输入的回路 时序逻辑电路&…...

C#都可以找哪些工作?

在国内学习C#&#xff0c;可以找的工作主要是以下4个&#xff1a; 1、游戏开发 需要学习C#编程、Unity引擎操作、游戏设计和3D图形处理等。 2、PC桌面应用开发 需要学习C#编程、WinForm框架/WPF框架、MVVM设计模式和UI/UX设计等。 3、Web开发 需要学习C#编程、ASP.NET框架…...

机器学习Python使用scikit-learn工具包详细介绍

一、简介 Scikit-learn是一个开源的机器学习库&#xff0c;用于Python编程语言。它建立在NumPy、SciPy和matplotlib这些科学计算库之上&#xff0c;提供了简单有效的数据挖掘和数据分析工具。Scikit-learn库包含了许多用于分类、回归、聚类和降维的算法&#xff0c;包括支持向量…...

蓝桥杯真题 - 扫雷 - 题解

题目链接&#xff1a;https://www.lanqiao.cn/problems/549/learning/ 个人评价&#xff1a;难度 1 星&#xff08;满星&#xff1a;5&#xff09; 前置知识&#xff1a;无 整体思路 按题意模拟&#xff1b;为了减少不必要的“数组越界”判断&#xff0c;让数组下标从 1 1 1…...

vue3项目结合Echarts实现甘特图(可拖拽、选中等操作)

效果图&#xff1a; 图一&#xff1a;选中操作 图二&#xff1a;上下左右拖拽操作 本案例在echarts​​​​​​​示例机场航班甘特图的基础上修改​​​​​​​ 封装ganttEcharts组件&#xff0c;测试数据 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软件包管理工具&#xff0c;类似windows里面的setup,exe是Liux这系列操作系统里而的打包安装工具。 RPMI包的名称格式&#xff1a; Apache-1.3.23-11.i386.rpm “apache’” 软件名称“1.3.23-11” 软件的版本号&am…...

读取硬件板子上的数据

SSCOM工具&#xff0c;先要安装一个插件 这样就可以读到设备数据...

Cesium 实例化潜入潜出

Cesium 实例化潜入潜出 1、WebGL Instance 的原理 狭义的的WebGL 中说使用 Instance, 一般指使用 glDrawArraysInstanced 用于实例化渲染的函数。它允许在一次绘制调用中渲染多个相同的几何体实例&#xff0c;而无需为每个实例发起单独的绘制调用。 Three.js 就是使用这种方…...

java引入jedis并且关于开放redis端口问题

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:数据库 JavaEE专栏:JavaEE 软件测试专栏:软件测试 关注博主带你了解更多知识 目录 1. 引入jedis ​编辑 2. 关于java客户端开放redis端口问题 3. 连接redis服务器 redis服务器在官网公开了使用的协议: resp…...

【人工智能】用Python实现情感分析:从简单词典到深度学习方法的演进

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 情感分析是自然语言处理(NLP)中的一个重要任务,其目的是通过分析文本内容,识别出其中的情感极性,如正面、负面或中性。随着技术的不断…...

关系型数据库的完整性和一致性

完整性 1.实体完整性 - 每一个实体都是独一无二的&#xff0c;没有冗余 --主键/唯一索引 2.参照完整性 - 外键 3.域完整性 - 存储的数据都是有效的数据 --数据类型/数据长度/非空约束/检查约束/ 检查约束&#xff1a; alter table tb_score add constraint ck_score_scmar…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

go 里面的指针

指针 在 Go 中&#xff0c;指针&#xff08;pointer&#xff09;是一个变量的内存地址&#xff0c;就像 C 语言那样&#xff1a; a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10&#xff0c;通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...