莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          Erlang ring benchmark

          Posted on 2007-08-04 17:46 dennis 閱讀(1533) 評論(0)  編輯  收藏 所屬分類: erlangmy open-source
              這是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各實現了一個版本,有興趣的看看這里這里


          主站蜘蛛池模板: 横山县| 木兰县| 定陶县| 商洛市| 彝良县| 怀柔区| 格尔木市| 乐至县| 江都市| 双柏县| 鞍山市| 泌阳县| 汝州市| 巩留县| 北川| 鸡西市| 杭锦后旗| 万山特区| 栾城县| 宝应县| 察雅县| 香格里拉县| 奉贤区| 阿拉善盟| 丹凤县| 会同县| 中山市| 鹰潭市| 克拉玛依市| 科尔| 吐鲁番市| 沙洋县| 靖州| 蓬莱市| 日照市| 偃师市| 保靖县| 阳西县| 高雄县| 石台县| 鹰潭市|