Erlang:erl shell在构建大型数据结构后挂起

时间:2009-12-30 20:21:14

标签: erlang

正如a previous question的答案所示,我尝试使用Erlang proplist来实现前缀trie。

代码看起来效果不错......但是,由于某些原因,它在交互式shell中效果不佳。当我尝试运行它时,shell会挂起:

> Trie = trie:from_dict(). % Creates a trie from a dictionary
% ... the trie is printed ...
% Then nothing happens

我看到新的trie打印到屏幕上(即,trie:from_dict()的调用已经返回),然后shell就会挂起。没有新的>提示符出现,^g没有做任何事情(但^c最终会将其删除)。

使用一个非常小的字典(/usr/share/dict/words的前50行),挂起只持续一两秒(并且trie几乎立即构建)......但它似乎随着大小呈指数增长字典(100个单词需要5或10秒,我没有耐心尝试更大的单词列表)。此外,当shell挂起时,我注意到beam.smp进程开始吃掉 lot 的内存(介于1到2个演出之间)。

那么,是否有任何明显可能导致此shell挂起和令人难以置信的内存使用?


一些不同的评论:

  • 我预感垃圾收集器有问题,但我不知道如何分析或创建实验来测试它。

  • 我尝试使用eprof进行分析,但没有任何明显的信息显示出来。

  • 这是我的“添加字符串到trie”功能:

add([], Trie) ->
    [ stop | Trie ];

add([Ch|Rest], Trie) ->
    SubTrie = proplists:get_value(Ch, Trie, []),
    NewSubTrie = add(Rest, SubTrie),
    NewTrie = [ { Ch, NewSubTrie } | Trie ],
    % Arbitrarily decide to compress key/value list once it gets
    % more than 60 pairs.
    if length(NewTrie) > 60 ->
            proplists:compact(NewTrie);
        true ->
            NewTrie
    end.

2 个答案:

答案 0 :(得分:3)

问题是(除了其他人? - 请参阅我的评论),无论Ch是否已经存在,您总是在您的proplist Tries中添加新的{Ch,NewSubTrie}元组。

而不是

NewTrie = [ { Ch, NewSubTrie } | Trie ]

你需要这样的东西:

NewTrie = lists:keystore(Ch, 1, Trie, {Ch, NewSubTrie})

答案 1 :(得分:2)

你真的不是在这里建立一个特里。您的最终结果实际上是一个随机排序的proplists列表,在列表行走时需要在每个级别进行全面扫描。尝试通常是基于数组(或列表)中的位置的隐含排序。

这是一个使用元组作为存储机制的实现。调用集只重建根和直接路径元组 (注意:可能必须使该对三倍(添加大小)使删除工作具有任何效率)

我相信erlang元组实际上只是数组(以为我在某处读过),所以查找应该超级快,修改可能是直截了当的。也许这对阵列模块来说速度更快,但我还没有真正了解它。

此版本还存储任意值,因此您可以执行以下操作:

1> c(trie).
{ok,trie}
2>  trie:get("ab",trie:set("aa",bar,trie:new("ab",foo))). 
foo
3> trie:get("abc",trie:set("aa",bar,trie:new("ab",foo))).
undefined
4>

代码(整个模块):note2:假设小写非空字符串键

-module(trie).
-compile(export_all).
-define(NEW,{ %% 26 pairs, to avoid cost of calculating a new level at runtime
 {undefined,nodepth},{undefined,nodepth},{undefined,nodepth},{undefined,nodepth},
 {undefined,nodepth},{undefined,nodepth},{undefined,nodepth},{undefined,nodepth},
 {undefined,nodepth},{undefined,nodepth},{undefined,nodepth},{undefined,nodepth},
 {undefined,nodepth},{undefined,nodepth},{undefined,nodepth},{undefined,nodepth},
 {undefined,nodepth},{undefined,nodepth},{undefined,nodepth},{undefined,nodepth},
 {undefined,nodepth},{undefined,nodepth},{undefined,nodepth},{undefined,nodepth},
 {undefined,nodepth},{undefined,nodepth}
 }
).
-define(POS(Ch), Ch - $a + 1).

new(Key,V) -> set(Key,V,?NEW).

set([H],V,Trie) -> 
 Pos = ?POS(H),
 {_,SubTrie} = element(Pos,Trie),
 setelement(Pos,Trie,{V,SubTrie});

set([H|T],V,Trie) ->
 Pos = ?POS(H),
 {SubKey,SubTrie} = element(Pos,Trie),
 case SubTrie of
  nodepth -> setelement(Pos,Trie,{SubKey,set(T,V,?NEW)});
  SubTrie -> setelement(Pos,Trie,{SubKey,set(T,V,SubTrie)})
 end.

get([H],Trie) -> 
 {Val,_} = element(?POS(H),Trie),
 Val;
get([H|T],Trie) ->
 case element(?POS(H),Trie) of
  {_,nodepth} -> undefined;
  {_,SubTrie} -> get(T,SubTrie)
 end.
相关问题