假设您有一个简单的函数,对于较大的值可能会非常昂贵:
fact(0) -> 1;
fact(N) -> N * fact(N - 1).
在哪里可以找到使用dets
缓存(或记忆)函数值的简单示例?
任何其他易于记忆的方式都将受到高度赞赏。
答案 0 :(得分:17)
根据您的情况,您还可以使用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.
答案 1 :(得分:4)
我们的想法是,每当您要求进行重计算时,如果您已经对其进行了评估,则会立即检查缓存。如果是,您只需返回存储的值。如果没有,您必须先评估新值并存储它,然后再将其返回给最终用户。
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中。在init函数中你应该创建DETS表,事实/ 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.
显然,即使这对大数字有帮助,您也必须考虑为每个步骤向查找表添加条目的额外成本。考虑到引入缓存的原因(我们假设计算非常繁重,因此查找插入时间无关紧要),这应该是完全正常的。