閱讀84 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Erlang ring benchmark

這是Programming Erlang第8章節的一個練習,創建N個process,連接成一個圈,然後在這個圈子裏發送消息M次,看看時間是多少,然後用另一門語言寫同樣的程序,看看時間是多少。我自己寫的版本在處理3000個進程,1000次消息循環(也就是300萬次消息傳遞)時花了5秒多,後來去google別人寫的版本,竟然讓我找到一個98年做的benchmark:Erlang vs. java,也是同樣的的問題。測試的結果是Erlang性能遠遠大於java,這也是顯然的結果,Erlang的process是輕量級、無共享的,而java的線程是os級別的,兩者創建的cost不可同日而語。詳細的比較請看這裏
    不過我分析了這個測試裏的Erlang代碼,存在問題,並沒有完成所有的循環,進程就結束了,這對比較結果有較大的影響。原始代碼如下:

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

然後執行下zog:run(3,3),你將發現消息繞了兩圈就結束了,第三圈根本沒有進行,不知道測試者是什麼用意。依照現在的執行300萬次消息傳送竟然隻需要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.
修改之後,執行zog:run(3000,1000),也就是3000個進程,1000次消息循環,總共300萬次消息傳遞,結果在2.5秒左右,這也是相當驚人的結果。有人用haskell和scheme各實現了一個版本,有興趣的看看這裏這裏

文章轉自莊周夢蝶  ,原文發布時間2007-08-04

最後更新:2017-05-18 10:32:30

  上一篇:go  java求字符串型邏輯表達式的bool值
  下一篇:go  一點領悟吧,關於消息傳遞與lambda算子