Erlang字计数器

时间:2011-05-28 07:00:01

标签: erlang count word parallel-processing

我正在尝试在Erlang中创建一个多线程(?)程序:

  1. 读入大文件(600mb)
  2. 将消息触发到一组已创建的进程,这些进程包含从文件中读取的行
  3. 创建的进程处理单词并存储在hashtree中
  4. 创建进程然后将hashtree激活回主
  5. master打印树。
  6. 到目前为止,我认为我已经完成了前三个...我无法弄清楚如何通过在每次插入时打印出每个键 - 哈希对来测试我的树。

    主线程:

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

    感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

我发现您的程序存在很多问题,但要回答您的问题,您需要了解如何使用receive来让您的流程相互通信。我建议您阅读前几章here - 特别是this one。话虽如此,这是我对代码的评论:

  • 知道最终目标是什么会很有帮助。代码没有多大意义,特别是因为Size从未使用过所有进程都是相同的。
  • 目前还不清楚为什么要产生任何东西。产生W进程并将每一行发送到所有这些进程都是一个陷阱 - 由于IO开销(发送到每个进程时必须复制文本),这最终会比不产生速度慢得多。您最终会在它们之间发送类似(W)(600MB)(2)的内容。让人惊讶。
  • 您可能需要dict或orddict而不是gb树。见dict:update_counter / 3。有关详细信息,另请参阅this。使用ets表可能有意义,但我又不确定目标是什么。
  • string:在这种情况下,应该使用tokens / 2而不是re:split / 2 - 你不需要re的开销来进行简单的空格分割。

答案 1 :(得分:0)

我不知道如果我完全关注,我想你正试图让字数统计。

您可以在循环中添加一条看起来像

的新消息

{print} - &gt;         io:format(“〜p~n”,gb_trees:to_list(Tree)),         io:format(“Words~p~n”,gb_trees:size(Tree)),         loop(Size,NewTree);

另外我不明白为什么你把每一行发送到所有进程..这只是为了练习?或试图建立一些可以快速计算单词的东西?这不会。

我很少暗示: 您还可以使用stringtokens来分割单词。 http://www.erlang.org/doc/man/string.html

我会使用单词process而不是thread,因为Erlang声称它会创建轻量级进程而不是线程 http://www.erlang.org/doc/efficiency_guide/processes.html

答案 2 :(得分:0)

最大的问题是这项练习的目的是什么?它是真正的工作还是只是某种学习。如果它应该是真正的产品你不能很好地开始。你应该首先询问这些数据的来源,然后你应该尝试确定瓶颈的位置。在你的情况下,你说的是600MB。保存在内存中的数据并不多。如果你必须从某个存储中读取它,你的解决方案将强烈依赖于这个存储,因为从CPU的角度来看,如果你期望平均字大小为10B,则600MB字可以是大约60M字,如果你期望平均6B字,则可以是100M字。你有多快可以计算100M字?如果您使用基于某些东西的k / v解决方案,您可以在一个商用CPU核心上以1s的速度完成。听起来很疯狂?不,它比第一眼看上去容易。如果您的解决方案基于Judy Array或您自己手工制作的实现,您可以相对轻松地获得这样的结果,如果您不是通过C编码吓到的话。那么您可以多快地从数据存储中获取这个野兽?如果您使用商品磁盘,您可以在6s内读取数据!如果你更好地调整它,你可以做得更好但是在相同的时间内完成处理将是挑战。你为什么试着让它平行?只有当您必须真正从存储中读取数据时,才会出现这种情况。例如,当您正在阅读之前由某个流程存储的数据时,情况并非如此。在这种情况下,您可以更快地访问此数据,因为它将在高概率的缓存中。在这种情况下,它将以非常不同的方式表现。例如,您可以随机访问数据。以上阅读时间只能通过从传统磁盘顺序读取来实现。 SSD表现不同,但整体数据吞吐量不是更好。因此,只有你能够足够快地充满你的CPU工作,那么你的并行性努力是值得的。那么最大的问题将是如何放弃数据并对其进行分区。如需灵感,请查看Tim Bray's Wide Finder Pro­ject。但请记住,首先使用刷新的IO缓存来测量Wide Finder项目,因此可以从缓存中随机访问数据。即使在这种情况下你也可以使用Erlang,但不要忘记它的一个优点就是与其他语言接口,特别是C和我会指向NIF。

如果目的只在Erlang练习,我的问题是为什么树?为什么不ets:update_counter/3?如果您认为ets不够快,请尝试处理字典而不是gb_trees。在您自己控制的过程中使用它时,它不会那么脏。考虑在memmory中读取整个文件但使用二进制文件。密集使用binary模块,所以......