测试起因
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)].
-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)].
-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倍,很强大。
测试中,每个消息占据的内存大小跟消息本身居然没有关系,实在想不通啊。
测试仅是自己给自己发消息,没测试很多个进程,相互间发消息的情况,这个代码暂时还不知道怎么写。