Ответ
Мемоизация — это техника оптимизации, при которой результаты выполнения "дорогих" функций сохраняются (кэшируются), чтобы избежать повторных вычислений с теми же входными аргументами.
В Python самый простой способ реализовать мемоизацию — использовать декоратор functools.lru_cache
.
Использование lru_cache
Декоратор lru_cache
(Least Recently Used) кэширует результаты вызовов функции. Если функция вызывается повторно с теми же аргументами, результат возвращается из кэша, а не вычисляется заново.
Пример:
import time
from functools import lru_cache
# maxsize - максимальное количество хранимых результатов
# Если maxsize=None, кэш будет неограниченным
@lru_cache(maxsize=128)
def fibonacci(n):
print(f"Вычисляем fibonacci({n})...")
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# Первый вызов - все значения будут вычислены
print("Первый вызов:")
start = time.time()
result = fibonacci(10)
print(f"Результат: {result}, время: {time.time() - start:.6f} сек")
# Второй вызов - результат будет взят из кэша мгновенно
print("nВторой вызов:")
start = time.time()
result = fibonacci(10)
print(f"Результат: {result}, время: {time.time() - start:.6f} сек")
Важные аспекты и ограничения:
- Хешируемые аргументы: Все аргументы функции должны быть хешируемыми (числа, строки, кортежи, frozenset). Списки и словари использовать нельзя.
- Чистые функции:
lru_cache
лучше всего подходит для "чистых" функций, результат которых зависит только от входных аргументов и не имеет побочных эффектов. - Потокобезопасность: Кэш является потокобезопасным.
Когда lru_cache
недостаточно?
lru_cache
реализует in-memory кэш в рамках одного процесса. Для более сложных сценариев требуются другие решения:
- Распределенное кэширование: Если приложение работает в нескольких процессах или на нескольких серверах, необходим внешний кэш, такой как Redis или Memcached. Это позволяет всем экземплярам приложения использовать общий кэш.
- Персистентное кэширование: Если нужно, чтобы кэш сохранялся между перезапусками приложения, данные следует сохранять на диск, например, с помощью
joblib.Memory
или в базу данных.