10Jul/081
Erlang Ring Code
Erlang Ring Benchmark Problem:
In the Programming Erlang book by Joe Armstrong, we find this problem at the end of the Concurrent Programming chapter.
Write a ring benchmark. Create N processes in a ring. Send a message round the ring M times so that a total of N * M messages get sent. Time how long this takes for different values of N and M. Write a similar program in some other programming language you are familiar with. Compare the results. Write a blog, and publish the results on the Internet!
My contribution to the already growing list of Erlang Ring Benchmark problem. However this is just the code for the Erlang, a N ring setup and M messages moving around the ring in parallel.
-module(ring). -export([benchmark/2]). %% run benchmark for N processes and M messages. benchmark(N, M) -> Pids = makering(N), for(1, M, fun() -> spawn(fun() -> start(message, Pids) end) end). %% setting up the process ring for sending %% messages & return the Pids array makering(M) -> %% create the processes Pids = for(1, M, fun() -> spawn(fun() -> loop() end) end), [Head | _T] = Pids, %% now setup the ring. one simple init loop to make each %% each process aware of its next process in the ring %% we need to pass Head head here as we want to connect %% the last process back to the head. connect(Head, Pids), %% return the Pids Pids. %% If only two elements are left in the list just point %% the first process to the next process. And point the %% the last process to the first process. connect(Head, [H, N]) -> H ! {next, N}, N ! {next, Head}; %% Connect the head and the next element and move to the %% next elements connect(Head, [H, N | T]) -> H ! {next, N}, connect(Head, [N | T]). %% send message from the beggining of the %% ring. start(Mesg, Pids) -> [Head|T] = Pids, Head ! {lists:last(T), Mesg, length(Pids)}. %% order a mass suicide for all process nodes killall(Pids) -> lists:foreach(fun(Pid) -> Pid ! die end, Pids). %% message waiting loop. waits for message and sends %% it to the next process node. commits sepukku if %% it is ordered to die. loop() -> receive %% now that we have the next pid, we move into the %% the listening loop for that function. remember %% the loop/1 will share the same Pid as this, so %% no worries. {next, NextPid} -> io:format("Set next for ~p as ~p~n", [self(), NextPid]), wait(NextPid) end. wait(NextPid) -> receive {From, Mesg, NumHops} when NumHops >= 0 -> io:format("~w from ~p to ~p~n", [Mesg, From, self()]), NextPid ! {self(), Mesg, NumHops - 1}, wait(NextPid); die -> void end. %% custom for loops for(N,N,F) -> [F()]; for(M,N,F) -> [F()|for(M + 1, N, F)].
July 1st, 2009 - 17:14
Try this…
-module(proces).
-export([do_ring/1, loopx/0, loopm/3, do_test/0]).
do_ring(N) -> A = spawn(proces,loopx,[]),
A ! {create, A, N-1},
A.
loopm(Pid0,NextPid, N) -> receive
0 ->
%% _ = io:format(“~s ~b~n”,["0 in node", N]),
%% _ = io:format(“~w ~n”, [now()]),
loopm(Pid0, NextPid, N);
die ->
%% _ = io:format(“~s ~b~n”,["die in node", N]),
NextPid ! die;
M when NextPid == Pid0 ->
%% _ = io:format(“~b ~s ~b~n”,[M,"in node!", N]),
NextPid ! M-1,
loopm(Pid0, NextPid, N);
M ->
%% _ = io:format(“~b ~s ~b~n”,[M,"in node", N]),
NextPid ! M,
loopm(Pid0, NextPid, N)
end.
loopx() -> receive
{create, Pid0, 0} ->
loopm(Pid0,Pid0, 0);
{create, Pid0, N} ->
A = spawn(proces, loopx, []),
A ! {create, Pid0, N-1},
loopm(Pid0,A,N)
end.
do_test() ->
P = do_ring(5000),
_ = io:format(“~w ~n”, [now()]),
P ! 1000,
_ = io:format(“~w ~n”, [now()]).