Эрланг параллелизма в кругах


Я новичок в Эрланг (2 дня если честно) и я очень ценю некую экспертную оценку. Я делаю эти упражнения и был немного застрял на этом этапе:

2) написать функцию, которая запускает процессы Н в кольцо, и отправляет сообщение M раз вокруг все процессы в кольцо. После сообщения были отправлены процессы должны корректно завершить.

С некоторой помощью от так, я придумал рабочее решение, но я не уверен насчет его качества в любом аспекте: понимание языка, стиля кодирования, эффективности и т. д.

Я буду благодарен за любые комментарии у вас есть.

-module (concur).
-export ( [pingCircle/3, pingCircle/2] ).

pingCircle (Names, Message, TTL) ->
    Processes = lists:map (fun (Name) -> spawn (?MODULE, pingCircle, [Name, nobody] ) end, Names),
    ProcessPairs = lists:zip (Processes, rot1 (Processes) ),
    lists:map (fun ( {Process, Recipient} ) -> Process ! {setRecipient, Recipient} end, ProcessPairs),
    Circle = lists:map (fun ( {Process, _} ) -> Process end, ProcessPairs),
    hd (Circle) ! {Message, TTL - 1, lists:last (Circle) }.

rot1 ( [] ) -> [];
rot1 ( [Head | Tail] ) -> Tail ++ [Head].

pingCircle (Name, Recipient) ->
    receive
        {setRecipient, NewRecipient} ->
            pingCircle (Name, NewRecipient);
        {Message, 0, Originator} ->
            io:format ("~s received ~p with TTL 0 and dying.~n", [Name, Message] ),
            if
                Originator == self () -> io:format ("All dead.~n");
                true -> Recipient ! {Message, 0, Originator}
            end;
        {Message, TTL, Originator} ->
            io:format ("~s received ~p with TTL ~p.~n", [Name, Message, TTL] ),
            if
                Originator == self () -> Recipient ! {Message, TTL - 1, Originator};
                true -> Recipient ! {Message, TTL, Originator}
            end,
            pingCircle (Name, Recipient)
    end.


514
10
задан 30 июля 2011 в 02:07 Источник Поделиться
Комментарии
3 ответа

Вы можете заменить

spawn (?MODULE, pingCircle, [Name, nobody] )

с

spawn (fun() -> pingCircle(Name, nobody) end)

Это действие позволяет не экспортировать pingCircle/2 от модуля.
Также рекомендуется использовать spawn_link вместо того, чтобы метать икру, потому что это помогает избежать проиграли процессы.

5
ответ дан 13 ноября 2012 в 06:11 Источник Поделиться

lists:map (fun ( {Process, Recipient} ) -> Process ! {setRecipient, Recipient} end, ProcessPairs)

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


Circle = lists:map (fun ( {Process, _} ) -> Process end, ProcessPairs),

Если я что-то пропустил, список вы получите от карты будет такой же, как ваш оригинальный процессах списке, который вы построили ProcessPairs от. Так что вы можете просто использовать процессы и избавиться от круга.

4
ответ дан 9 сентября 2011 в 12:09 Источник Поделиться

Я читаю Эрланг Программирование Чезарини и Томпсон, который представляет по сути один и тот же вопрос. Я пробовал несколько разных способов, и в конечном итоге с ниже код. По сути, это создает кольцо из хвоста (сам()) в голову (FirstNode), затем впрыскивает сообщения пользователя в FirstNode, следует бросить сообщение. Тест (функция) создает кольцо из миллиона нитей и отправляет тысячи сообщений.

Редактировать:

Модифицированный подождать перед отправкой бросить курить, и отображается количество сообщений, которые передаются на мастер-узле. Обратите внимание, что на Erlang Программирование, проблема не указать, что сообщения должны останавливаться на составителя, ни то, что сообщения начинаются любые узлы, кроме первого узла.

-module(ring2).
-export([test/0, test_race/0, start/3, node_loop/2, fire_quit_later/1]).

test() -> ring2:start(2, 1000000, "Hey").

start(NumMsgs, NumProcs, Message) ->
FirstNode = send_messages(create_node(NumProcs, self()), NumMsgs, Message),
spawn(ring2, fire_quit_later, [FirstNode]),
MessageCount = node_loop(FirstNode, 0),
io:format("Done at ~p. Master node processed ~p messages.~n", [calendar:local_time(), MessageCount]).

fire_quit_later(FirstNode) ->
receive
after 20000 -> io:format("Firing quit at ~p~n", [calendar:local_time()]), FirstNode ! quit
end.

send_messages(FirstNode, 0, _) -> FirstNode;
send_messages(FirstNode, NumMsgs, Message) ->
FirstNode ! Message,
send_messages(FirstNode, NumMsgs - 1, Message).

create_node(0, NextNode) -> NextNode;
create_node(NodeNumber, NextNode) -> create_node(NodeNumber - 1, spawn(ring2, node_loop, [NextNode, 0])).

node_loop(NextNode, MessageCount) ->
receive
quit -> NextNode ! quit, MessageCount;
Message -> NextNode ! Message, node_loop(NextNode, MessageCount + 1)
end.

test_race() ->
self() ! quit,
receive
quit -> done
after 1000 -> {error, no_message}
end.

0
ответ дан 2 октября 2013 в 03:10 Источник Поделиться