erlang进程间发送消息的性能

来源:互联网 发布:台州淘宝美工 编辑:程序博客网 时间:2024/05/16 18:51

测试起因

     erlang 语言是建议多建进程(erlang自己的进程,不是操作系统进程),利用消息来协同进程,实现高并发。

     要实际在项目中使用,就必须知道erlang进程创建的速度,进程间消息通信的速度,消息通信对内存的影响。

     根据这些性能数据,才好判断进程需要切分到什么样的粒度,才能预估一个系统架构的大致性能水平。

     书上没说,所以自己动手测试下。

erlang进程创建的速度

        erlang的进程,其实在内部实现中,仅是个数据结构,根据 erlang程序设计 书中的代码,测试了下,启动10000个进程,平均每个进程需要1us~3us之间,每个进程的内存开销约3K。 如果仅新增了一个数据结构,这个时间消耗大了点。

       但不管启动多少个进程,从操作系统上看到的erl的线程数都是8个。

       测试过程如下:

Eshell V5.9.2  (abort with ^G)
1> processor:max(10000).       %表示创建1万个进程,不销毁
Max allowed processes: 32768
Process spawn time= 3.0 (4.1) usecond
24
2> processor:max(10000).
Max allowed processes: 32768
Process spawn time= 2.0 (4.0) usecond
24
3> processor:max(10000).
Max allowed processes: 32768
Process spawn time= 4.0 (4.1) usecond
24
4> processor:max(10000).
Max allowed processes: 32768
 
=ERROR REPORT==== 26-Sep-2012::11:10:06 ===
Too many processes
 
3次执行前后,内存增长分别为:
第一次:33.05078125 M
第二次:27.36328125 M
第三次:25.4453125  M
 
代码如下:
-module(processor).
-export([max/1]).

max(N) ->
    Max = erlang:system_info(process_limit),
    io:format("Max allowed processes: ~p~n", [Max]),
    statistics(runtime),
    statistics(wall_clock),
    L = for(1, N, fun()-> spawn(fun()-> wait() end) end),
    {_, Time1} = statistics(runtime),
    {_, Time2} = statistics(wall_clock),
    %   lists:foreach(fun(Pid) -> Pid ! die end, L),
    U1 = Time1 *1000 / N,
    U2 = Time2 *1000 / N,
    io:format("Process spawn time= ~p (~p) microsecond~n",
             [U1, U2]),
    1+5,    
    21+3.

wait() ->
    receive
        die ->
            void
    end.

for(N, N, F) ->
    [F()];
for(I, N, F) ->
    [F()|for(I+1, N, F)].

 

erlang的消息

 
 
写了个测试程序,自己给自己发消息
%%% yqmsg.erl
-module(yqmsg).
-export([max/1,wait/0]).

max(N) ->
    io:format("PID=~p,Max Message: ~p~n", [self(),N]),
    statistics(runtime),
    statistics(wall_clock),
    L = for(1, N, fun()->self()!{testmsg,"1234567890abcdefghijklmnopqrstuvwxyz#$%^ABCDEFGHIJ"}   end),
    {_, Time1} = statistics(runtime),
    {_, Time2} = statistics(wall_clock),
    U1 = Time1 *1000/ N,
    U2 = Time2 *1000/ N,
    io:format("PID=~p,TotalTime=~p(~p), Avgtime= ~p (~p) usecond~n", [self(),Time1,Time2,U1, U2]),
    wait().
wait() ->
    receive
        {testmsg,X} -> io:format("Message: ~p~n", [X])
    end.

for(N, N, F) ->
    [F()];
for(I, N, F) ->
    [F()|for(I+1, N, F)].
 
查内存占用是用操作系统的命令: ps auxmm|egrep -i 'smp|RSS',  看的是vsz列的值,按运行前后的差值除以1024得到下面的结果。
 
当消息字符串是20个字节时,发送 1百万个消息:
     每个消息CPU耗时:1.44us,  总耗时:1.601us
     erl进程的内存增长:63.58M
 
当消息字符串是50个字节时,时间和内存消耗没变化(神奇,时间没变可以理解,为什么内存消耗也没变化,测试方法有什么问题呢?
当消息继续改大后,内存增值连小数点后面都没变。新消息是:{testmsg,"1234567890abcdefghijklmnopqrstuvwxyz#$%^ABCDEFGHIJ",9999999,999999.99,1234567890123,eeooff}
 
当消息字符串是50个字节时,发送 1千万个消息:
     每个消息CPU耗时:2.058us,  总耗时:2.3032us
     erl进程的内存增长:647.9688M
 
 
当消息字符串是50个字节时,发送 10万个消息:
     每个消息CPU耗时:多次测试,大约在0.6~0.9 us,  总耗时:0.7~1.1 us
     erl进程的内存增长:多次测试,结果分别为 8.79M,8.94M,4.02M,5.02M
 
测试环境说明
    PC Server,CPU是 2G主频,操作系统是安装在vmware虚拟机上,RedHat 2.6.18-164.el5 #1 SMP。
 
总结
    做架构设计时,基本上可以按每个消息 1us 的性能来考虑,而且在消息数量百倍增长的情况下,性能下降约3倍,很强大。
    测试中,每个消息占据的内存大小跟消息本身居然没有关系,实在想不通啊。
    测试仅是自己给自己发消息,没测试很多个进程,相互间发消息的情况,这个代码暂时还不知道怎么写。
 
 
 
原创粉丝点击