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

时间: 2024-09-12 22:41:57

Erlang ring benchmark的相关文章

Scala Ring Benchmark

  Scala实现的ring benchmark: import scala.actors.Actorimport scala.actors.Actor._import java.util.concurrent.CountDownLatchcase class Message()class Process(m:Int,p:Actor,latch:CountDownLatch) extends Actor{   var next=p   def act{    loop{      recvAnd

【原创】在CentOS 5.7上通过YUM安装Erlang的坑爹经历(更新)

      想要在虚拟机上的 Linux 环境下,重新搞一下 RabbitMQ 的相关实验,所以重新折腾了下如何操作: Since RabbitMQ is written in Erlang, we need to have installed the language libraries to run the broker.       首先还是要把 Erlang 的安装搞定,最简单的方式是直接重 官网 上下载源码包或rpm包再安装,但是我是个喜欢折腾的人,所以我选择了另外一种"比较笨拙&qu

PostgreSQL 11 preview - pgbench 变量、函数扩展 - 暨pgbench 自定义 benchmark讲解

标签 PostgreSQL , pgbench , 压测 , 变量 , tpc-b , 自定义压测 背景 pgbench是PostgreSQL软件包中的一款benchmark软件,纯C编码,效率高,压测方便. 内置TPC-B benchmark测试,同时支持自定义benchmark. 详细文档见 https://www.postgresql.org/docs/10/static/pgbench.html pgbench 自定义benchmark脚本支持的语法 变量赋值的语法 压测需要生成输入变量

计划在C++建立仿Erlang式的分布式并行机制

梳理了下需求,大体如下: 进程(Process).进程是Erlang中一个虚拟的运行单位.既不是操作系统的进程,也不 是线程,而是比线程更加轻量的单位,更接近于协程. 命名进程(NamedProcess).命名进程的好处是,你可以向一个不知道进程ID的进程发送 消息.由于进程可能会宕掉(crash),进程ID可能会发生变化,所以在考虑了异常的环境下 ,命名进程降低了编码的难度(你不再需要考虑进程crash检测和重建连接的过程). 进程邮箱(Mailbox).每个进程都拥有一个自己的邮箱,其他进程

【原创】调用 proc_lib:spawn/1 和 erlang:spawn/1 有什么区别

在<Erlang OTP 设计原则>中的 "Sys与Proc_Lib" 一节中有如下描述:  模块 proc_lib 中的函数可以用于实现一种特殊进程,遵照 OTP 设计原则,但不使用标准行为.它们也可以用于实现用户自定义的(非标准)行为. 怎样算是符合 OTP 设计原理而又不使用标准行为的 "特殊进程"呢?  以一种可以让进程放入监督树的方式启动: 支持 sys 的调试功能: 关注系统消息 . 什么是系统消息?       系统消息是用于监督树中的.带

erlang otp-erlang 服务器端编程 错误提示 variable &amp;amp;#39;State&amp;amp;#39; is unbound

问题描述 erlang 服务器端编程 错误提示 variable 'State' is unbound -module(gen_server_template). %% gen_server_template -behaviour(gen_server). -export([start_link/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/

CI框架源码阅读笔记5 基准测试 BenchMark.php

由于BenchMark是CI中第一个加载的core组件,因此我们的分析首先从该组件开始.BenchMark的含义非常明确,使用过BenchMark工具的同学应该比较清楚,这是一个基准组件.既然是BenchMark,我们便可大胆猜想,BM组件的主要功能就是记录程序的运行时间.内存使用.cpu使用等情况.     这个组件结构较简单,只有一个marker内部变量和三个对外的接口:   1 Elapsed_time 2 Mark 3 Memory_usage 下面一个个展开来看:   1. mark

如何实施Benchmark标准测试(之一)---问题的提出及Tpc-C标准

标准|问题 如何实施Benchmark标准测试 ---问题的提出及Tpc-C标准 Last Updated: Monday, 2004-10-18 16:36 Eygle       1.问题的提出 不管你实施怎样的一个系统,你可能都考虑过这样的一系列问题: 我应该采购怎样的设备?我的系统性能如何?我的系统能够承受多少用户?我的系统能够承受多少并发?性能问题会在何时出现?我将在何时升级? 显然,回答这些问题并非那么简单,更多的人是根据经验给出一个经验值,用来评估系统.但是在大系统设计过程中,经验

Yaf 2.1性能测试(Yaf 2.1 Benchmark)

Thanks to Ruilog agian for his work of second benchmark of Yaf 2.1. Yaf 2.1 (docs) did a lot of work to improve performance and reduce memory usage, so let's take a look at the result(Yaf 2.1重写了很多逻辑来提升性能, 并且降低内存使用率, 改进结果见测试对比): First of all, I have t