Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs
На этом занятии
мы с вами рассмотрим еще один декоратор lru_cache из модуля functools. Как можно
понять из его названия, он позволяет кэшировать результаты вызываемых объектов,
в частности, функций.
Вообще
аббревиатура LRU означает «Least
Recently Used», то есть это кэш, который сохраняет результаты наиболее часто
используемых вычислений, уменьшая нагрузку на процессор для ускорения работы
программы.
Принцип работы
декоратора lru_cache, применительно
к какой-либо функции, заключается в сохранении в памяти (кэше) результатов ее
работы. Когда функция вызывается с одними и теми же аргументами повторно, её
результат берётся непосредственно из кэша, минуя повторное исполнение самого
тела функции. При этом кэш постоянно обновляется, чтобы в нем присутствовали
только наиболее употребительные элементы.
Давайте
посмотрим на конкретном примере использование этого декоратора. Чтобы лучше
была видна работа декоратора lru_cache, мы возьмем
рекурсивную функцию, которая вычисляет n-е число Фибоначчи:
def fib(n):
if n <= 1:
return 1
return fib(n-1) + fib(n-2)
Функция fib() специально не
оптимизирована. Замерим время ее выполнения без каких-либо декораторов:
print(timeit.timeit(lambda: fib(30), number=1)) # 0.0881322999484837
И с декоратором lru_cache:
@functools.lru_cache()
def fib(n):
if n <= 1:
return 1
return fib(n-1) + fib(n-2)
print(timeit.timeit(lambda: fib(30), number=1)) # 2.340017817914486e-05
Как видите,
время выполнения значительно сократилось из-за кэширования предыдущих вычислений
функции fib().
По умолчанию
декоратор lru_cache()
ограничивается 128 элементами. Но мы можем установить свое ограничение любым
числом степени 2, например, 2 элемента:
@functools.lru_cache(maxsize=2)
def fib(n):
...
Соответственно,
в кэше будут сохраняться два последних вызова функции fib() и время
выполнения увеличится:
print(timeit.timeit(lambda: fib(30), number=1)) # 0.004572800127789378
Или же
установить размер кэша в 256 элементов:
@functools.lru_cache(maxsize=256)
def fib(n):
...
Тогда получим гораздо
более быстрое выполнение рекурсивной функции.
В случаях, когда
требуется неограниченный размер кэша, параметр maxsize следует задать
значением None:
@functools.lru_cache(maxsize=None) # неограниченный эш
def fib(n):
...
Итак, декоратор lru_cache работает по
следующим правилам:
- В кэше хранится
ограниченное количество записей (это число задаётся параметром maxsize,
значение которого должно быть степенью двойки).
- Когда кэш заполняется,
самые старые записи автоматически удаляются, освобождая пространство для новых
записей.
- Каждый раз,
когда функция вызывается с новым набором аргументов, соответствующая запись
добавляется в кэш.
Мало того
функция, декорированная с помощью lru_cache, приобретает два встроенных метода:
print(fib.cache_info()) # возвращает информацию о текущем состоянии кэша
fib.cache_clear() # очищает кэш
Таким образом, декоратор
lru_cache помогает оптимизировать производительность приложений, сокращая
затраты на постоянные обращения к медленным операциям (таким как сетевые
запросы, операции ввода-вывода или длительные вычисления). Это простое и
эффективное решение для повышения скорости обработки запросов и снижения
нагрузки на систему.
Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs