Автор оригинала: Robin Andrews.
Улучшение эффективности программ Python с использованием мемузаризации
Некоторые из вас могут быть знакомы с последовательностью Фибоначчи, которая известна как в математике, так и в компьютерном программировании. Последовательность образована путем добавления вместе каждого из предыдущих двух терминов для создания следующего срока в последовательности. Он имеет свое происхождение в рассмотрении размножения кроликов и оказаться многими по-настоящему интересными и удивительными свойствами. Эта статья конкретно конкретно относится к последовательности FIBONACCI, но я добавлю некоторые ссылки на интересные статьи, которые вы можете проверить, если вы хотите узнать больше об этом.
Последовательность Фибоначчи начинается следующим образом:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
Следующее число найдено, добавляя два номера до него в последовательности.
Итак, например
2 рассчитывается путем добавления значений 1 и 1, исходя из них, 3 рассчитывается, добавляя значения 1 и 3, исходя из которых вычисляется, а 5 рассчитывается путем добавления значений 2 и 3 1 и 3, исходя из которых. и так далее!
Иногда последовательность начинается с разных начальных значений, в том числе общ .| 1, 1 вместо 0, 1 Но узел того, как каждый термин построен, остается последовательным.
Числа фибоначчи с Python
Последовательность Фибоначчи часто используется для иллюстрации концепции Рекурсия В программировании, который является очень мощным методом со многими приложениями. Основная идея состоит в том, что мы нарушаем большую проблему на более мелкие проблемы одного и того же типа и решаем эти меньшие проблемы в качестве средства для решения первоначальной проблемы.
С точки зрения компьютерного кода, он обычно принимает форму функции, которая указывает Базовый чехол содержит вызов к себе (функция вызывает сама), а чья возвращаемый подходит ближе к Базовый чехол с каждым вызовом.
Так, например, функция для возврата nth Число Фибоначчи в Python выглядит так:
def fib(n):
"""
Returns the n-th Fibonacci number.
"""
if n == 0 or n == 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(10))
Совершенствование сложности времени Python Programs с использованием мемузаризации
Теперь вышеуказанный код хорошо и хорошо, кроме …. Есть ваша проблема.
Попробуйте этот код, который раз выполняет исполнение FIB (N) для N :
import time
def fib(n):
"""
Returns the n-th Fibonacci number.
"""
if n == 0 or n == 1:
return n
return fib(n - 1) + fib(n - 2)
n = 20
start = time.perf_counter()
fib(n)
end = time.perf_counter()
print("Seconds taken: {:.7f}".format(end - start))
Этот код времена выполнения FIB (N) для N Отказ На моей машине я получил Снятые секунды: 0,0066919
Это кажется хорошо, но как насчет более высокого значения для N ? Скажи 40-е место Число Фибоначчи?
На моей машине я получил Снятые секунды: 118.2504081
Очевидно, что это проблема, как мы рассматриваем только N И уже время исполнения нецелесообразно.
Можете ли вы подумать, почему алгоритм, как он стоит, занимает так много времени, чтобы выполнить?
Ответ заключается в том, что многие значения рассчитаны несколько раз. Например, используя обозначения F1 Для первого номера фибоначчи F2 Для второго и т. Д. Мы можем видеть, что
Для того, чтобы рассчитать F6 Мы рассчитаем F4 и F5 и для того, чтобы рассчитать F5 Мы рассчитаем F3 и F4 и для того, чтобы рассчитать F4 Мы рассчитаем F2 и F3 и т.п.
С относительно небольшим значением для N Эти дополнительные расчеты не имеют большого значения, но нам не нужно далеко идти по последовательности, чтобы добраться до точки, где повторяющиеся расчеты так сильно составляют, что время выполнения становится непрактично.
Можете ли вы придумать подход к решению этой проблемы?
Памяза Python с использованием lru_cache
Существует способ резко сократить время выполнения функции FIBONACCI, но сохраняя предыдущие результаты. Необработанный термин для этого мемузаризация Отказ Что это значит в этом случае, это то, что один раз, скажем, F3 был рассчитан, результат хранится в кэше, так что в следующий раз значение F3 нужен, вместо расчета его, добавляя F1 и F2 Программа может получить доступ к результату непосредственно из кэша. И то же самое идет для всех остальных ранее встречающихся ценностей N Отказ
Реализация этой идеи в Python Очень просто, если мы используем доступные для нас инструменты, как вы можете видеть в коде ниже. Это использует lru_cahce от Functools модуль. lru в этом обозначает Наименее недавно использованный Наименее недавно использованное (LRU) кэш-память организует предметы в порядке использования, что позволяет вам быстро определить, какой элемент не использовался в течение самого длинного времени.
Список кода Memoation Python
from functools import lru_cache
import time
@lru_cache
def fib(n):
"""
Returns the n-th Fibonacci number.
"""
if n == 0 or n == 1:
return n
return fib(n - 1) + fib(n - 2)
n = 40
start = time.perf_counter()
fib(n)
end = time.perf_counter()
print("Seconds taken: {:.7f}".format(end - start))
На моей машине я получил Снятые секунды: 0,0000443 Отказ Это довольно какое-то улучшение на 118.2504081 секунды за то же значение N !
Ручная кэширование
Хотя использование «магии» @lru_cache Декоратор в порядке для практических целей, вы можете получить более глубокое понимание того, как воспоминание работает, реализуя кэширование «вручную». Для тех, кто хочет сделать это, я предоставил листинг кода ниже, показывающий один способ, которым можно сделать, передавая кэш Словарь вместе с каждым вызовом функций.
# With manual caching
def fib(n, cache={}):
if n in cache:
return cache[n]
if n == 0 or n == 1:
return n
result = fib(n - 1) + fib(n - 2)
cache[n] = result
return result
print(fib(40))
Есть большое количество приложений для мемузаризация в питоне. После того, как вы понимаете концепцию и имеете некоторый опыт использования его, у вас будет мощный инструмент для вашего инструмента управления программированием, чтобы значительно улучшить производительность вашего кода.