這是Programming Erlang第8章節(jié)的一個(gè)練習(xí),創(chuàng)建N個(gè)process,連接成一個(gè)圈,然后在這個(gè)圈子里發(fā)送消息M次,看看時(shí)間是多少,然后用另一門語(yǔ)言寫同樣的程序,看看時(shí)間是多少。我自己寫的版本在處理3000個(gè)進(jìn)程,1000次消息循環(huán)(也就是300萬(wàn)次消息傳遞)時(shí)花了5秒多,后來(lái)去google別人寫的版本,竟然讓我找到一個(gè)98年做的benchmark:Erlang vs. java,也是同樣的的問(wèn)題。測(cè)試的結(jié)果是Erlang性能遠(yuǎn)遠(yuǎn)大于java,這也是顯然的結(jié)果,Erlang的process是輕量級(jí)、無(wú)共享的,而java的線程是os級(jí)別的,兩者創(chuàng)建的cost不可同日而語(yǔ)。詳細(xì)的比較請(qǐng)看
這里 不過(guò)我分析了這個(gè)測(cè)試?yán)锏腅rlang代碼,存在問(wèn)題,并沒(méi)有完成所有的循環(huán),進(jìn)程就結(jié)束了,這對(duì)比較結(jié)果有較大的影響。原始代碼如下:
-module(zog).
%% This is a test program that first creates N processes (that are
%% "connected" in a ring) and then sends M messages in that ring.
%%
%% - September 1998
%% - roland
-export([start/0, start/1, start/2]).
-export([run/2, process/1]). % Local exports - ouch
start() -> start(16000).
start(N) -> start(N, 1000000).
start(N, M) -> spawn(?MODULE, run, [N, M]).
run(N, M) when N < 1 ->
io:format("Must be at least 1 process~n", []),
0.0;
run(N, M) ->
statistics(wall_clock),
Pid = setup(N-1, self()),
{_,T1} = statistics(wall_clock),
io:format("Setup : ~w s", [T1/1000]),
case N of
1 -> io:format(" (0 spawns)~n", []);
_ -> io:format(" (~w us per spawn) (~w spawns)~n",
[1000*T1/(N-1), N-1])
end,
statistics(wall_clock),
Pid ! M,
K = process(Pid),
{_,T2} = statistics(wall_clock),
Time = 1000*T2/(M+K),
io:format("Run : ~w s (~w us per msg) (~w msgs)~n",
[T2/1000, Time, (M+K)]),
Time.
setup(0, OldPid) ->
OldPid;
setup(N, OldPid) ->
NewPid = spawn(?MODULE, process, [OldPid]),
setup(N-1, NewPid).
process(Pid) ->
receive
M ->
Pid ! M-1,
if
M < 0 -> -M;
true -> process(Pid)
end
end.
我將process修改一下:
process(Pid) ->
receive
M ->
Pid ! M-1,
io:format("form ~w to ~w~n",[self(),Pid]),
if
M < 0 -> -M;
true -> process(Pid)
end
end.
然后執(zhí)行下zog:run(3,3),
你將發(fā)現(xiàn)消息繞了兩圈就結(jié)束了,第三圈根本沒(méi)有進(jìn)行,不知道測(cè)試者是什么用意。
依照現(xiàn)在的執(zhí)行300萬(wàn)次消息傳送竟然只需要3毫秒!我修改了下了下代碼如下:
-module(zog).
%% This is a test program that first creates N processes (that are
%% "connected" in a ring) and then sends M messages in that ring.
%%
%% - September 1998
%% - roland
-export([start/0, start/1, start/2]).
-export([run/2, process/2]). % Local exports - ouch
start() -> start(16000).
start(N) -> start(N, 1000000).
start(N, M) -> spawn(?MODULE, run, [N, M]).
run(N, M) when N < 1 ->
io:format("Must be at least 1 process~n", []),
0.0;
run(N, M) ->
statistics(wall_clock),
Limit=N-N*M+1+M,
Pid = setup(N-1,Limit,self()),
{_,T1} = statistics(wall_clock),
io:format("Setup : ~w s", [T1/1000]),
case N of
1 -> io:format(" (0 spawns)~n", []);
_ -> io:format(" (~w us per spawn) (~w spawns)~n",
[1000*T1/(N-1), N-1])
end,
statistics(wall_clock),
% io:format("run's Pid=~w~n",[Pid]),
Pid ! M,
K = process(Pid,Limit),
% io:format("run's K=~w~n",[K]),
{_,T2} = statistics(wall_clock),
Time = 1000*T2/(M+K),
io:format("Run : ~w s (~w us per msg) (~w msgs)~n",
[T2/1000, Time, (M+K)]),
T2/1000.
setup(0,Limit, OldPid) ->
OldPid;
setup(N,Limit, OldPid) ->
NewPid = spawn(?MODULE, process, [OldPid,Limit]),
setup(N-1, Limit,NewPid).
process(Pid,Limit) ->
receive
M ->
Pid ! M-1,
% io:format("from ~w to ~w and M=~w~n",[self(),Pid,M]),
if
M <Limit -> -M;
true -> process(Pid,Limit)
end
end.
修改之后,執(zhí)行zog:run(3000,1000),也就是3000個(gè)進(jìn)程,1000次消息循環(huán),總共300萬(wàn)次消息傳遞,
結(jié)果在2.5秒左右,這也是相當(dāng)驚人的結(jié)果。有人用haskell和scheme各實(shí)現(xiàn)了一個(gè)版本,有興趣的看看
這里和
這里