Простой пример для запоминания Эрланга - PullRequest
10 голосов
/ 23 июля 2010

Предположим, у вас есть простая функция, которая может стоить довольно дорого для больших значений:

fact(0) -> 1;
fact(N) -> N * fact(N - 1).

Где найти простой пример кэширования (или запоминания) значений функции с помощью dets?

Любой другой способ для легкого запоминания будет высоко оценен.

Ответы [ 2 ]

18 голосов
/ 23 июля 2010

В зависимости от вашего случая вы также можете использовать словарь процесса для запоминания:

fact(0) -> 1;
fact(N) ->
    case erlang:get({'fact', N}) of
        F when is_integer(F) ->
            F;
        'undefined' ->
            F = N * fact(N-1),
            erlang:put({'fact', N}, F),
            F
    end.
4 голосов
/ 23 июля 2010

Идея состоит в том, что каждый раз, когда вы запрашиваете тяжелый расчет, вы сразу же проверяете в кеше, если уже оценивали его.Если да, вы просто возвращаете сохраненное значение.Если нет, вам нужно оценить новое значение и сохранить его, прежде чем вернуть его конечному пользователю.

A dict , а не таблица dets, также может работать.

(следующее решение не проверено)

-module(cache_fact).

-export([init/0, fact/1]).

init() ->
    {ok, _} = dets:open_file(values, []).

fact(N) ->
    case dets:lookup(values, N) of
      [] ->
        Result = do_fact(N), 
        dets:insert_new(values, {N, Result}),
        Result;
      [{N, Cached}] ->
        Cached
    end.

do_fact(0) ->
    1;
do_fact(N) ->
    N * do_fact(N-1).

Возможно, вы захотите инкапсулировать все это в универсальный сервер Erlang .В функции init вы должны создать таблицу DETS, функция fact / 1 должна представлять ваш API, и вы должны реализовать логику в функциях handle_call.

Более хорошим примером может быть написание более короткого сервиса для URL, кэшированного.

Как предполагает @Zed, было бы целесообразно также сохранить частичные результаты, чтобы избежать дальнейших перерасчетов.Если это так:

-module(cache_fact).

-export([init/0, fact/1]).

init() ->
    {ok, _} = dets:open_file(values, []).

fact(0) ->
    1;
fact(N) ->
    case dets:lookup(values, N) of
      [] ->
        Result = N * fact(N-1),
        dets:insert_new(values, {N, Result}),
        Result;
      [{N, Cached}] ->
        Cached
    end.

Очевидно, что даже если это помогает для больших чисел, необходимо учитывать дополнительные затраты на добавление записи в таблицу поиска для каждого шага.Учитывая причины, по которым было введено кэширование (мы предполагаем, что вычисления очень тяжелые, поэтому время вставки поиска незначительное), это должно быть совершенно нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...