综述
上一篇是测试单个进程自己给自己发消息的速度, 差不多是每消息 1us。
如果编写实际的erlang程序,一定是一堆进程,进程之间相互发消息,为验证这种情况下消息收发的性能,写了个测试程序,程序的思路是:
1)创建N个进程
2)这N个进程,每个进程都再创建出一个接收进程,然后往那个进程发包,发M个包后,再给那个进程发个终止消息,给主进程发给自杀消息,然后自己终止
3)接收进程仅负责收包,收到终止消息时退出,收到其他消息时继续
4)主进程在创建了N个进程后,开始收消息,当收到N个进程的自杀消息后,大约统计时间并退出
测试结果
接下来的测试,M 我都设定为一百万,进程数和时间关键如下:
在1~100之间,性能下降低于线性,非常好; 到500个进程的时候,性能下降大大超过了线性。
进程数 | 总CPU耗时(ms) | 总流逝时间(ms) | 总CPU耗时增长 | 总流水时间增长 |
1 |
0000910 |
904 | ||
10 |
0025680 |
6753 | 28倍 | 7.5倍 |
100 |
0163900 |
41556 | 6.4倍 | 6.2倍 |
500 | 1290560 | 326016 | 7.9倍 | 7.8倍 |
1000 |
2602360 | 700928 | 2倍 | 2.1倍 |
从操作系统看, 运行过程中,CPU的 user部分可以占到 98%, erl进程的CPU使用率可到 399% (是虚拟机,就4个core)。
以下是测试过程中对 top 显示结果的随机截取,顺序是按时间顺序排列的。
可以看出erl的内存占用,是变大,然后变小,然后变大,但后期基本上变化幅度不大,都在300M左右。
从打印结果看,非常有序,不像操作系统的线程输出,一片混乱,证实了erlang进程调度是完全平均分配的官方说法,1000个进程的测试中,不按下面次序打印的就五六个进程左右。
测试环境
在租用的电信云主机上测试的。4cpu, 红帽的系统。
这批的云主机,使用的是华为的云平台,华为实际使用的是XEN虚拟化软件。
之后有在我们自己购买的PC Server上测试,安装了vmware云平台后再安装红帽系统,同样划出4个core(两个测试环境都没有打开超线程),
测试结果是:
华为云主机(XEN) TotalTime=174080(44086),
Vmware云主机 TotalTime=115240(29063)
Vmware云主机这性能的提升有 25% 啊,物理CPU还差一点,是E5 2GHz,难道是因为XEN太差了?
华为云主机的信息:
# uname -r
2.6.18-164.el5
# cat /proc/cpuinfo
processor : 3
vendor_id : GenuineIntel
cpu family : 6
model : 47
model name : Intel(R) Xeon(R) CPU E7- 4830 @ 2.13GHz
stepping : 2
cpu MHz : 2128.088
cache size : 24576 KB
physical id : 0
siblings : 4
core id : 3
cpu cores : 4
apicid : 6
fpu : yes
fpu_exception : yes
cpuid level : 11
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc pni cx16 popcnt lahf_lm
bogomips : 4255.64
clflush size : 64
cache_alignment : 64
address sizes : 44 bits physical, 48 bits virtual
代码
-module(yqmsg2).
-export([start/2,mainwait/2,sendor/2]).
start(Thrs, Msgs) ->
io:format("PID=~p,Max Message: ~p~n", [self(),Msgs]),
statistics(runtime),
statistics(wall_clock),
PPID=self(),
L = for(1, Thrs, fun()-> spawn(fun()-> sendor(PPID,Msgs) end) end),
io:format("mainwait begin ~p ~n",[Thrs]),
mainwait(0,Thrs),
{_, Time1} = statistics(runtime),
{_, Time2} = statistics(wall_clock),
U1 = Time1 *1000 /Msgs ,
U2 = Time2 *1000 /Msgs,
io:format("PID=~p,TotalTime=~p(~p)ms, Avgtime= ~p (~p) usecond~n", [self(),Time1,Time2,U1, U2]),
1+1.
mainwait(N,N) ->
void;
mainwait(I,N) ->
receive
{sendordie} ->
io:format("I=~p,N=~p. ~n",[I,N]),
mainwait(I+1,N)
end.
sendor(PPID,Msgs) ->
Peer = spawn(fun()->recvor(0) end),
io:format("sendmsgs begin msg=~p,Peer=~p.~n",[Msgs,Peer]),
sendmsgs(1, Msgs,Peer),
io:format("sendmsgs end msg=~p,Peer=~p.~n",[Msgs,Peer]),
Peer!{die},
PPID!{sendordie},
io:format("sendor die PPID=~p, pid=~p,msgnum=~p.~n",[PPID,self(),Msgs]).
sendmsgs(N,N,PID) ->
PID!{testmsg,["1234567890abcdefghijklmnopqrstuvwxyz#$%^ABCDEFGHIJ",9999999,999999.99,1234567890123,eeooff]};
sendmsgs(I,N,PID) ->
PID!{testmsg,["1234567890abcdefghijklmnopqrstuvwxyz#$%^ABCDEFGHIJ",9999999,999999.99,1234567890123,eeooff]},
sendmsgs(I+1,N,PID).
recvor(N) ->
receive
{die} ->
io:format("recvor dir ~p.~n",[self()]),
void;
{testmsg,_} -> recvor(N+1)
end.
for(N, N, F) ->
[F()];
for(I, N, F) ->
[F()|for(I+1, N, F)].