Ответ
В Python кэширование можно реализовать несколькими способами, которые условно делятся на две категории: внутрипроцессное и распределенное.
1. Внутрипроцессное кэширование (In-memory)
Кэш хранится в оперативной памяти текущего процесса. Идеально подходит для ускорения повторных вызовов "тяжелых" функций с одинаковыми аргументами (мемоизация).
Решение: декоратор functools.lru_cache.
LRU (Least Recently Used) означает, что при заполнении кэша вытесняются самые давно неиспользуемые элементы.
import time
from functools import lru_cache
@lru_cache(maxsize=128)
def fetch_data(n: int) -> int:
"""Имитация долгой операции, например, запроса к БД."""
print(f"Выполняется сложный расчет для {n}...")
time.sleep(1)
return n * n
print(fetch_data(5)) # Расчет займет 1 секунду
print(fetch_data(5)) # Результат вернется мгновенно из кэша
print(fetch_data(10))# Расчет займет 1 секунду
print(fetch_data(10))# Результат вернется мгновенно из кэша
- Преимущества: Очень быстро, легко реализовать, входит в стандартную библиотеку.
- Недостатки: Кэш живет только в рамках одного процесса и сбрасывается при его перезапуске. Аргументы функции должны быть хешируемыми.
2. Распределенное кэширование (Distributed)
Кэш хранится во внешнем, независимом сервисе (например, Redis или Memcached). Используется в веб-приложениях и распределенных системах.
Задачи:
- Снижение нагрузки на базу данных.
- Обмен данными между разными процессами или серверами.
- Хранение сессий пользователей.
Пример с Redis:
import redis
import json
# Подключение к серверу Redis
r = redis.Redis(decode_responses=True)
def get_user_profile(user_id: int):
cache_key = f"user:{user_id}"
# 1. Проверяем наличие данных в кэше
cached_data = r.get(cache_key)
if cached_data:
print(f"Данные для user:{user_id} взяты из кэша Redis")
return json.loads(cached_data)
# 2. Если в кэше нет, получаем данные из БД (имитация)
print(f"Данные для user:{user_id} запрошены из БД")
db_data = {"id": user_id, "name": "Alice", "email": "alice@example.com"}
# 3. Сохраняем данные в кэш с временем жизни (TTL) 60 секунд
r.set(cache_key, json.dumps(db_data), ex=60)
return db_data
get_user_profile(123) # Запрос к БД
get_user_profile(123) # Данные из кэша
- Преимущества: Доступен из любого процесса/сервера, устойчив к перезапускам приложений, гибкие настройки времени жизни (TTL).
- Недостатки: Требует развертывания и поддержки отдельного сервиса, более медленный доступ по сравнению с in-memory кэшем из-за сетевых задержек.