代码之家  ›  专栏  ›  技术社区  ›  Yuval Adam

Erlang回忆录的简单示例

  •  10
  • Yuval Adam  · 技术社区  · 15 年前

    假设您有一个简单的函数,对于较大的值,它可能会非常昂贵:

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

    dets ?

    任何其他方便记忆的方式将不胜感激。

    2 回复  |  直到 15 年前
        1
  •  4
  •   Roberto Aloi    15 年前

    我们的想法是每次你要求 重的 计算时,如果已经计算过缓存,则立即签入缓存。如果是,只需返回存储值。如果没有,则在将新值返回给最终用户之前,必须计算并存储它。

    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 generic server

    一个更好的例子是为url编写一个更简短的服务,缓存。

    -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.
    

    显然,即使这有助于处理大量数据,您也必须考虑为每个步骤向查找表中添加条目的额外成本。考虑到引入缓存的原因(我们假设计算非常繁重,因此查找插入时间无关紧要),这应该很好。

        2
  •  18
  •   Jakub M.    12 年前

    根据您的情况,您还可以使用 process dictionary 回忆录:

    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.