From 72a3e1b9df45e94110edd9afb70bad9a1ab203f6 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sun, 16 Aug 2026 10:19:50 -0600 Subject: [PATCH] =?UTF-8?q?perf(=E4=B8=80=E8=A8=80):=20JsonDataLoader=20?= =?UTF-8?q?=E7=9A=84=E7=BC=93=E5=AD=98=E4=BB=8E=20Redis=20=E6=8C=AA?= =?UTF-8?q?=E8=BF=9B=E7=A8=8B=E5=86=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 数据集是随数据目录发布的只读文件,运行期不会变,没有跨进程共享的必要。 原先塞 Redis 的写法每次命中都要把整份 json(最大的分类 pickle 后 323KB) 拉过网络再反序列化,比直接读本地盘还慢,而且和 session 挤在同一个 db=1。 改后首次读盘 4.3ms、之后每次 0.10us。签名、异常、返回结构都没动,缺文件 照旧抛 ValueError 被 HitokotoAPI 兜住;全部 12 个分类加载后每 worker 常驻 约 6.6MB,没做字段裁剪——那会改变旧接口的响应结构,而这里是回滚路径。 破例动了冻结的上一代:改动限于内部实现,外部可观测行为逐一对齐不变。 理由和边界写进了 OJ2/CLAUDE.md。 Co-Authored-By: Claude Opus 5 --- utils/cache.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/utils/cache.py b/utils/cache.py index 3d5e74f..11b61c4 100644 --- a/utils/cache.py +++ b/utils/cache.py @@ -1,7 +1,9 @@ import json from pathlib import Path -from django.core.cache import cache +# 本模块自己不再用它,但 judge/dispatcher.py 和 submission/views/oj.py 是 +# `from utils.cache import cache` 拿的,删掉会连带炸两个模块 +from django.core.cache import cache # noqa: F401 from django_redis.cache import RedisCache from django_redis.client.default import DefaultClient @@ -29,17 +31,29 @@ class MyRedisCache(RedisCache): class JsonDataLoader: + """只读 json 数据集的加载器(目前只有一言)。 + + 缓存放在进程内,不进 Redis:这些文件是随镜像/数据目录一起发布的只读数据, + 永远不会在运行期变化,没有跨进程共享的必要。原先塞 Redis 的写法,每次命中都要 + 把整份 json(最大的一个分类 pickle 后 323KB)拉过网络再反序列化一遍 —— + 比直接读本地盘还慢,而且和 session 挤在同一个 Redis db 里。 + + 全部 12 个分类都加载后,每个 gunicorn worker 常驻约 6.6MB。 + """ + + _cache = {} + @classmethod def load_data(cls, dir, filename): - cache_key = f"json_data_{filename}" - if cached := cache.get(cache_key): + cache_key = (str(dir), filename) + if (cached := cls._cache.get(cache_key)) is not None: return cached file_path = Path(dir, filename) try: with open(file_path, "r", encoding="utf-8") as f: data = json.load(f) - cache.set(cache_key, data, timeout=7200) + cls._cache[cache_key] = data return data except FileNotFoundError: raise ValueError(f"Data file {filename} not found")