Эрланг счетчик слов - PullRequest
       26

Эрланг счетчик слов

1 голос
/ 28 мая 2011

Я пытаюсь создать многопоточную (?) Программу на Erlang, которая:

  1. Читает в большом файле (600 МБ)
  2. Отправляет сообщения группе созданных процессов, содержащих строки, прочитанные из файла
  3. Созданные процессы обрабатывают слово и сохраняют в хэш-дереве
  4. созданный процесс затем запускает хэш-дерево обратно к мастеру
  5. Мастер печатает дерево.

Пока, я думаю, что я выполнил первые три ... Я не могу понять, как проверить свое дерево, распечатывая каждую пару ключ-хэш каждый раз, когда они вставляются.

Основная нить:

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

1 голос
/ 29 мая 2011

Я вижу много вещей не так с вашей программой, но чтобы ответить на ваш вопрос, вам нужно научиться использовать receive, чтобы ваши процессы могли общаться друг с другом.Я бы рекомендовал прочесть первые несколько глав здесь , в частности этой .При этом, вот мои комментарии о коде:

  • Было бы полезно узнать, какова конечная цель.Код не имеет большого смысла, особенно потому, что Size никогда не используется, поэтому все процессы одинаковы.
  • Непонятно, почему вы вообще что-то порождаете.Создание W-процессов и отправка каждой из них каждой из них является ловушкой - в конечном итоге это будет намного медленнее, чем не создание из-за накладных расходов ввода-вывода (текст должен копироваться при отправке каждому процессу).В итоге вы отправите между ними что-то вроде (W) (600 МБ) (2).Yikes.
  • Вы можете захотеть диктовать или приговор вместо дерева gb.Смотрите dict: update_counter / 3.Также см. this для получения более подробной информации.Использование таблицы ets может иметь смысл, но, опять же, я не уверен, какова цель.
  • string: tokens / 2 следует использовать вместо re: split / 2 в этом случае - вам не нужноиздержки re для простого разделения пробелов.
0 голосов
/ 29 мая 2011

Самый большой вопрос - какова цель этого упражнения? Это для реальной работы или только для обучения. Если это должен быть настоящий продукт, вы не начинаете его хорошо. Сначала вы должны задать вопрос, откуда поступят эти данные, а затем попытаться определить, где будет пробка. В вашем случае речь идет о 600МБ. Это не так много данных, чтобы хранить их в памяти. Если вам придется читать его из какого-то хранилища, ваше решение будет сильно зависеть от этого хранилища, поскольку с точки зрения процессора 600 МБ слов могут составить около 60 слов, если вы ожидаете средний размер слова 10В или 100 слов, если ожидаете среднего слова 6Б. Как быстро вы можете считать 100Mwords? Если вы используете решение k / v, основанное на чем-то очень быстром, вы можете сделать это за 1 с на одном стандартном ядре ЦП. Звучит безумно? Нет, это проще, чем кажется на первый взгляд. Если вы основываете свое решение на чем-то вроде Judy Array или на своей собственной ручной реализации, вы можете достичь такого результата сравнительно легко, если не будете бояться кодирования на C. Так как быстро вы можете сыт по горло этим зверем? из хранилища данных? Если вы используете товарные диски, вы можете прочитать данные за 6 секунд! Если вы настроите это лучше, вы можете сделать лучше, но сделать это в сопоставимое время с обработкой будет проблемой. Почему вы пытаетесь сделать это параллельно? Вышесказанное верно только в том случае, если вам действительно нужно читать данные из хранилища. Это не так, например, когда вы читаете данные, которые были сохранены каким-то процессом непосредственно перед этим. В этом случае вы можете получить доступ к этим данным намного быстрее, потому что они будут в кеше с высокой вероятностью. В этом случае все будет вести себя совсем по-другому. Например, вы можете получить доступ к данным в случайном порядке. Выше времени чтения может быть достигнуто только путем последовательного чтения с классических дисков. SSD ведет себя по-разному, но общая пропускная способность данных не на порядок лучше. Так что, только если вы можете достаточно быстро накорректировать работу своего процессора, ваши усилия по параллелизму того стоят. Тогда самой большой проблемой будет то, как подать данные и разбить их на части. Для вдохновения вы можете взглянуть на Проект широкого поиска Тима Брея . Но имейте в виду, что первый проект Wide Finder не был измерен с очищенными кешами ввода-вывода, поэтому это был случай, когда к данным можно было получить произвольный доступ из кешей. Даже в этом случае вы можете использовать Erlang, но не забывайте, что одной из его сильных сторон является взаимодействие с другими языками, особенно C, и я укажу вам на NIFs.

Если цель практиковать только в Эрланге, мой вопрос: почему деревья? Почему бы не ets: update_counter / 3 ? Если вы считаете, что ets недостаточно быстр, попробуйте использовать словарь процесса вместо gb_trees. Это не так грязно, когда вы используете его в процессе под вашим собственным контролем. Вы можете прочитать весь файл в памяти, но работать с двоичным файлом. Интенсивно используйте бинарный модуль и так ...

0 голосов
/ 28 мая 2011

Не знаю. Если я достаточно следую, думаю, вы пытаетесь подсчитать количество слов.

Вы можете добавить новое сообщение в ваш цикл, которое выглядит как

{печать} -> io: format ("~ p ~ n", gb_trees: to_list (Tree)), io: format («Слова ~ 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

...