1번은 동시에(simultaneous)를 어떻게 처리해야 할지 모르것다.
해외 답을 봐도 '동시'에 실행하는 답은 없는 것 같은데 먼가 내가 핀트를 잘못잡고 있는듯,
머 어짜피 atomic이라 해도 erlang 내부에서 말이지, chapter 20.1을 보면
"등록된 프로세스를 만들때 마다 우리는 잠재적인 순차적 병목을 만들고 있다" 라고 적힌것을 보면 erlang 내부에서 적당히 처리해주는 것 같다. IO 쪽에서 이 내용이 나오느데 이걸 하드에도 기록하나;
머 하여간 2번 문제는 적당히 풀었다.
코드가 병렬화 되어 있지 않습니다. 수정한 버전은 나중에 올리겠습니다.
-module(erl8p2).
-export([main/2]).
makeRing(N) ->
Pids = for(1,N, fun ringNode/0),
LastElm = lists:last(Pids),
[LastElm | Pids].
destroyRing(RingElmPids) ->
[_|T] = RingElmPids,
lists:foreach(fun(Pid) -> Pid ! die end, T).
ringNode() ->
spawn(fun loop/0).
loop() ->
receive
{ring, [], _Request, Dest, _Result} ->
% io:format("Last Node:~p ~p~n",[ring, Msg, pid_to_list(self())]);
Dest ! {ring,_Result},
loop();
{ring, [H|T], Request, _Dest, _Result} ->
% io:format("Received:~p to ~p~n",[ring, Msg, pid_to_list(H)]),
H ! {ring, T, Request, _Dest, _Result},
loop();
die -> void
end.
for(N,N,Fun) -> [Fun()];
for(I,N,Fun) -> [Fun()|for(I+1,N,Fun)].
sendRingMsg(RingElmPids, Msg) ->
[H|T] = RingElmPids,
H ! {ring, T, Msg, self(), []},
receive
{ring, Results} -> Results
end.
stopWatch(Fun) ->
statistics(wall_clock),
statistics(runtime),
Fun(),
{_, Time1} = statistics(wall_clock),
{_, Time2} = statistics(runtime),
[Time1, Time2].
main(N,M) ->
RingElmPids = makeRing(N),
[Time1, Time2] = stopWatch(fun() -> for(1,M, fun() -> sendRingMsg(RingElmPids, "Hello World") end) end),
io:format("Ring benchmark tim = ~p (~p) ms~n", [Time1, Time2]),
destroyRing(RingElmPids).
;; 결과는 아래와 같다.
21> erl8p2:main(10000,10).
Ring benchmark tim = 7894 (6896) ms
fun이 local function 보다는 느리고 apply보다는 빠른 연산이라고 하는데,
"2.1 Myth: Funs are slow"
http://www.erlang.org/doc/efficiency_guide/myths.html
나중에 fun이나 바꿔야할 것 같다.
...언제나 느끼는 것이지만 짧은 영어 실력에서 나오는 변수명은 참 눈물난다.
그 때문에 짧은 설명은 붙이자면,
makeRing, destoryRing은 ringNode라 불리는 (뒷부분에선 ringElm로 개명한다..?!)
각 ring을 구성하는 element들의 집합으로 구성되는데,
(나중에 고쳐야될 것 같지만) 1->2->3->1 로 끝부분이 이어지도록 구성된다.
끝부분이 이어진다고 먼가 좋은 것이 있는 것은 아니고 그 덕분에 함수 성질에따라
H를 날리거나 그대로 이용한다.
destoryRing은 같은 element를 2번 지우면 안되니까 Head를 뺀 2, 3, 4, 1을 삭제하고,
sendRingMsg은 Head 로 메시지를 보내 다시 Head로 돌아오도록 만들때 이용한다.
loop는 각 element가 실제로 일을 처리하는 넘인데,
Request에 따라 일을 처리하고 Response에 결과를 추가하고 다음 elements(Pids의 Head)로 전송하는 역활을 한다.
여기서는 하는 일이 없으니 걍 Msg 받고 다음 elements로 메시지를 보내는 역활만 한다.
{ring, Pids, _Request, Dest, _Result} 는 대충 {ID, next Element Pids, Requtest, 마지막 결과 받을넘, 각노드의 결과}를 나타낸 Msg이다.
그니까
{ring, [], _Request, Dest, _Result} ->
Dest ! {ring,_Result},
next elemets Pids가 바닥난 한바퀴 돈 상황에서
Dest로 Results를 발신하고
그제서야 전체 Ring에 Request 를 보내 한바퀴 일 시키신
sendRingMsg께서는 결과를 받아보시고 종료한다.
------------------------------------------------------------------------------------------
수정본: spawn 한다음에 작업 마칠때 까지 기다려주려나? 메시지 통신으로 직접 알아야 하나?
-module(erl8p2).
-export([main/2]).
constructRing(N) ->
Pids = for(1,N, fun ringNode/0),
LastElm = lists:last(Pids),
[LastElm | Pids].
destructRing(RingElmPids) ->
[_|T] = RingElmPids,
lists:foreach(fun(Pid) -> Pid ! die end, T).
ringNode() ->
spawn(fun loop/0).
loop() ->
receive
{ring, [], _Request, Dest, _Result} ->
% io:format("Last Node:~p ~p~n",[ring, Msg, pid_to_list(self())]);
Dest ! {ring,_Result},
loop();
{ring, [H|T], Request, _Dest, _Result} ->
% io:format("Received:~p to ~p~n",[ring, Msg, pid_to_list(H)]),
H ! {ring, T, Request, _Dest, _Result},
loop();
die -> void
end.
for(N,N,Fun) -> [Fun()];
for(I,N,Fun) -> [Fun()|for(I+1,N,Fun)].
sendRingMsg(RingElmPids, Msg) ->
[H|T] = RingElmPids,
H ! {ring, T, Msg, self(), []},
receive
{ring, Results} -> Results
end.
timer(start) ->
statistics(wall_clock),
statistics(runtime);
timer(stop) ->
{_, Time1} = statistics(wall_clock),
{_, Time2} = statistics(runtime),
[Time1, Time2].
messageRing(RingElmPids) ->
spawn(fun() -> sendRingMsg(RingElmPids, "Hello World") end).
main(N,M) ->
RingElmPids = constructRing(N),
timer(start),
for(1, M, fun() -> messageRing(RingElmPids) end),
[Time1, Time2] = timer(stop),
io:format("Ring benchmark tim = ~p (~p) ms~n", [Time1, Time2]),
destructRing(RingElmPids).
49> erl8p2:main(10000,1000).
Ring benchmark tim = 281 (297) ms
sendRingMsg(RingElmPids, Msg) ->
[H|T] = RingElmPids,
H ! {ring, T, Msg, self(), []},
receive
{ring, Results} -> Results
end.