Erlang ring benchmark

    xiaoxiao2024-05-08  7

    这是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

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)