Erlang字计数器

| 我正在尝试用Erlang编写一个多线程(?)程序,该程序是: 读取大文件(600mb) 向包含已从文件读取的行的一组已创建进程发送消息 创建的进程处理单词并将其存储在哈希树中 创建的过程然后将哈希树激发回主节点 大师打印树。 到目前为止,我想我已经完成了前三个工作...我无法弄清楚如何在每次插入键/哈希对时打印出每个键/哈希对来测试我的树。 主线程:
-module(lineread).
-export([read/1]).

read(Wordlength) ->
    {ok, Input} = file:open(\"/home/ml/datasets/tweets/first60kTweets.txt\", [read]),
    Threads = makeThreads(Wordlength),
    read_lines(Input, Threads).

read_lines(Input, Threads) ->
    case file:read_line(Input) of
    eof ->
        file:close(Input);
    {ok, Line} ->
        send_to_all(Threads, Line),
        read_lines(Input, Threads)
    end.

send_to_all(Threads, Line) ->
    lists:foreach(fun(Pid) ->
                  Pid ! {line, Line} end,
              Threads).

makeThreads(NumThreads) ->
     [ spawn(counter, run, [N]) || N <- lists:seq(1, NumThreads) ].
其他线程:
-module(counter).
-export([run/1]).

%%entry point for the code
run(K) ->
    loop(K, gb_trees:empty()).

%%loops for a recieved message         
loop(Size, Tree) ->
    receive
    {line, Line} ->
        %%io:format(\"~p~n\", [Line]),
        Splits = re:split(Line, \" \"),
        NewTree = build_tree(Splits, Tree),
        loop(Size, NewTree);
    {char, Char} ->
        io:format(\"~p\", [Char])
        %%loop(Size, )
    end.

%%puts the data into a Tree...
build_tree([], Tree) ->
    Tree;
build_tree([W|R], Tree) ->
    case gb_trees:is_defined(W, Tree) of
    true ->
        I = gb_trees:get(W, Tree),
        NewTree = gb_trees:update(W, I + 1, Tree),
        io:format(I),
        build_tree(R, NewTree);
    false ->
        NewTree = gb_trees:insert(W, 1, Tree),
        %%io:format(\"~p/~n\"),
            build_tree(R, NewTree)
        end.
谢谢你的帮助。     
已邀请:
        我发现您的程序有很多问题,但是要回答您的问题,您需要学习如何使用ѭ2才能使进程相互通信。我建议在这里阅读前几章,尤其是本章。话虽如此,这是我对代码的评论: 了解最终目标是有帮助的。该代码没有多大意义,尤其是因为从未使用
Size
,因此所有进程都是相同的。 目前尚不清楚为什么要产生任何东西。生成W进程并将每一行发送给所有进程是一个陷阱-由于IO开销(与发送到每个进程时必须复制文本相比),这最终会比不产生新进程慢得多。您最终将在它们之间发送类似(W)(600MB)(2)的内容。 kes。 您可能想要一个字典或一个命令而不是一个gb树。参见dict:update_counter / 3。另请参阅此以获取更多详细信息。使用ets表可能很有意义,但是我不确定目标是什么。 在这种情况下,应使用string:tokens / 2而不是re:split / 2-对于简单的空格分割,您不需要re的开销。     
        我不会如果我很关注,我想您正在尝试获取字数。 您可以向循环添加新消息,如下所示 {print}->         io:format(\“〜p〜n \”,gb_trees:to_list(Tree)),         io:format(\“单词〜p〜n \”,gb_trees:size(Tree)),         循环(Size,NewTree); 同样,我也不明白为什么将每一行都发送到所有进程。这仅仅是为了练习吗?或尝试构建可以快速计算单词数的东西?这不会。 我有几点建议: 您也可以使用stringtokens分割单词。 http://www.erlang.org/doc/man/string.html 因为Erlang声称它创建的是轻量级进程而不是线程,所以我将使用process而不是thread一词。 http://www.erlang.org/doc/efficiency_guide/processes.html     
最大的问题是此练习的目的是什么?是用于实际工作还是仅用于某种​​学习。如果它应该是真正的产品,那么您将无法很好地启动它。您的第一个问题应该是这些数据将从何而来,然后您应该尝试确定瓶颈在哪里。您的情况是600MB。要保存在内存中的数据不是很多。如果必须从某些存储读取它,则解决方案将严重依赖于此存储,因为从CPU的角度来看,如果期望平均字大小为10B,则600MB的字大约为60Mword,如果期望平均字6B的话,则为100Mword。您能算多快100Mwords?如果您使用基于某事物的k / v解决方案非常快,则可以在一个商用CPU内核上以1s的速度完成它。听起来疯了吗?不,这比乍看之下容易。如果您的解决方案基于Judy Array之类的东西或您自己手工制作的trie实现,那么即使您不害怕用C编码,也可以相对容易地获得这样的结果。那么,您能以多快的速度从数据存储中厌倦这种野兽?如果使用商品磁盘,则可以在6s内读取数据!如果调整得更好,则可以做得更好,但是要在可比的时间内进行处理将是一个挑战。为什么要尝试使其平行?仅当您必须真正从存储中读取数据时,以上内容才适用。例如,当您正在读取之前由某个进程存储的数据时,情况并非如此。在这种情况下,您可以更快地访问此数据,因为它很有可能位于高速缓存中。在这种情况下,它们的行为将完全不同。例如,您可以随机访问数据。以上读取时间只能通过从传统磁盘顺序读取来实现。 SSD的行为有所不同,但总体数据吞吐量并没有好几个数量级。因此,只有当您足够快地完成CPU工作时,您对并行性的努力才是值得的。然后最大的问题将是如何馈送数据并对其进行分区。为了获得启发,您可以看一下Tim Bray的Wide Finder项目。但是请记住,第一个Wide Finder项目不是使用刷新的IO缓存来衡量的,因此可以从缓存中随机访问数据是这种情况。即使在这种情况下,您也可以使用Erlang,但不要忘记它的优势之一就是可以与其他语言(尤其是C)接口,我将向您介绍NIF。 如果只在Erlang中练习目的,我的问题是为什么要树?为什么不ets:update_counter / 3?如果您认为ets不够快,请尝试使用流程字典而不是gb_trees。当您在自己的控制下使用它时,它并没有那么脏。考虑读取内存中的整个文件,但可以使用二进制文件。大量使用二进制模块,因此...     

要回复问题请先登录注册