Обычно это все,что тебе нужно знать.Однако,существует множество вариантов:
memoize(function, options. );
NORMALIZER => function INSTALL => new_name SCALAR_CACHE => ‘MEMORY’ SCALAR_CACHE => [‘HASH’, %cache_hash ] SCALAR_CACHE => ‘FAULT’ SCALAR_CACHE => ‘MERGE’ LIST_CACHE => ‘MEMORY’ LIST_CACHE => [‘HASH’, %cache_hash ] LIST_CACHE => ‘FAULT’ LIST_CACHE => ‘MERGE’
DESCRIPTION
«Запоминание» функции ускоряет ее за счет обмена места на время. Это достигается путем кэширования возвращаемых значений функции в таблице. Если вы снова memoize функцию с теми же аргументами, запишется мемоиз и выдает значение из таблицы, вместо того, чтобы позволить функции вычислить значение заново.
Вот экстремальный пример.Рассмотрим последовательность Фибоначчи,определяемую следующей функцией:
# Вычислить числа Фибоначчи sub fib < my $n = shift; return $n if $n < 2; fib($n-1) + fib($n-2); >
Эта функция очень медленная.Почему? Чтобы вычислить волокно(14),она сначала хочет вычислить волокно(13)и волокно(12),а затем добавить результаты.Но чтобы вычислить волокно(13),сначала нужно вычислить волокно(12)и волокно(11),а затем оно возвращается и снова вычисляет волокно(12),несмотря на то,что ответ один и тот же.И оба раза,когда она хочет вычислить волокно(12),она должна вычислить волокно(11)с нуля,а затем она должна делать это снова каждый раз,когда она хочет вычислить волокно(13).Эта функция выполняет настолько много перезагрузок старых результатов,что для ее выполнения требуется очень много времени-волокно(14)делает 1200 дополнительных рекурсивных вызовов самому себе,чтобы вычислить и переписать вещи,которые она уже вычислила.
Телевизор не видит ТВ приставку. Что делать?
Эта функция является хорошим кандидатом на запоминание.Если запомнить функцию `fib’ выше,то она вычислит fiber(14)ровно один раз,первый раз,когда это необходимо,а затем сохранит результат в таблице.Затем,если вы снова попросите fiber(14),она выдаст вам результат из таблицы.При вычислении волокна(14),вместо того,чтобы вычислять волокно(12)дважды,оно делает это один раз;во второй раз ему нужно значение,которое он получит из таблицы.Он не вычисляет волокно(11)четыре раза;он вычисляет его один раз,а три раза получает его из таблицы.Вместо 1200 рекурсивных вызовов »волокна»,она делает 15.Это делает функцию примерно в 150 раз быстрее.
Ты можешь сделать запоминание самостоятельно,переписав функцию,вот так:
Или вы можете использовать этот модуль,вот так:
use Memoize; memoize(‘fib’); # Остальная часть функции fib, как в оригинальной версии.
Это позволяет легко включать и выключать запоминания.
Вот еще более простой пример:Я написал простой лучевой трассировщик;программа смотрела в определенном направлении,выясняла,на что она смотрит,а затем преобразовывала значение `color’ (обычно строка типа `красный’)этого объекта в красный,зеленый и синий пиксели,вот так:
Так как на картинке относительно мало объектов, есть только несколько цветов, которые просматриваются снова и снова. Memoizing ColorToRGB ускорил работу программы на несколько процентов.
Прошивка приставки от провайдера
DETAILS
Этот модуль экспортирует ровно одну функцию — memoize . Остальные функции в этом пакете — не ваше дело.
Вы должны сказать.
memoize(function)
где function — это имя функции, которую вы хотите запомнить, или ссылка на нее. memoize возвращает ссылку на новую, мемоизированную версию функции или undef в случае нефатальной ошибки. В настоящее время нефатальных ошибок нет, но они могут появиться в будущем.
Если function была именем функции, то memoize скрывает старую версию и устанавливает новую мемоизированную версию под старым именем, так что function, INSTALL => newname, SCALAR_CACHE => option, LIST_CACHE => option );
Каждый из этих вариантов является необязательным;вы можете включить некоторые,все или ни один из них.
INSTALL
Если вы укажете имя функции с помощью INSTALL , memoize установит новую мемоизированную версию функции под заданным вами именем. Например,
memoize(‘fib’, INSTALL => ‘fastfib’)
устанавливает мемоизированную версию fib как fastfib ; без INSTALL вариант было бы заменить старую fib с memoized версии.
Для предотвращения memoize от установки memoized версии в любом месте, используйте INSTALL => undef .
NORMALIZER
Предположим,твоя функция выглядит так:
Теперь все следующие вызовы к вашей функции полностью эквивалентны:
f(OUCH); f(OUCH, B => 2); f(OUCH, C => 7); f(OUCH, B => 2, C => 7); f(OUCH, C => 7, B => 2); (etc.)
Однако, если вы не сообщите Memoize , что эти вызовы эквивалентны, он не узнает об этом и вычислит значения для этих вызовов вашей функции отдельно и сохранит их отдельно.
Чтобы предотвратить это, предоставьте функцию NORMALIZER , которая превращает аргументы программы в строку таким образом, чтобы эквивалентные аргументы превращались в ту же строку. Функция NORMALIZER для приведенного выше f может выглядеть так:
Каждый из приведенных выше списков аргументов является результатом функции normalize_f , которая выглядит точно так же, как это:
OUCH,B,2,C,7
Вы бы сказали Memoize использовать этот нормализатор следующим образом:
memoize(‘f’, NORMALIZER => ‘normalize_f’);
memoize знает, что если нормализованная версия аргументов одинакова для двух списков аргументов, то он может безопасно найти значение, вычисленное для одного списка аргументов, и вернуть его в результате вызова функции с другим списком аргументов, даже если списки аргументов выглядят иначе.
Нормализатор по умолчанию просто конкапсулирует аргументы с символом 28 между ними.(В ASCII это называется FS или control-.)Это всегда корректно работает для функций только с одним строковым аргументом,а также когда аргументы никогда не содержат символ 28.Однако,это может запутать некоторые списки аргументов:
normalizer(«a 34», «b») normalizer(«a», «