这段时间我们的项目遇到广播包的一些性能问题,想起之前看到yufeng老大提到的1s广播40K包的问题,我也想测试测试我们机器的IO能力。
这次仅仅测试发包的能力,采用的是一对一的方式。
测试代码: READ THE FULL ARTICLE >>
这段时间我们的项目遇到广播包的一些性能问题,想起之前看到yufeng老大提到的1s广播40K包的问题,我也想测试测试我们机器的IO能力。
这次仅仅测试发包的能力,采用的是一对一的方式。
测试代码: READ THE FULL ARTICLE >>
erlang的bif中自带了md5计算函数,但是结果却是二进制的,即使转成list,也是10进制表示,google了一下得到一段代码用于获得字符串形式的md5结果(16位):
md5(S) ->
Md5_bin = erlang:md5(S),
Md5_list = binary_to_list(Md5_bin),
lists:flatten(list_to_hex(Md5_list)).
list_to_hex(L) ->
lists:map(fun(X) -> int_to_hex(X) end, L).
int_to_hex(N) when N < 256 ->
[hex(N div 16), hex(N rem 16)].
hex(N) when N < 10 ->
$0+N;
hex(N) when N >= 10, N < 16 ->
$a + (N-10).
英文链接 http://sacharya.com/md5-in-erlang/
开始时用的传统思路(循环读取):
recv(ClientSock, PacketLenOld, Remain)
when is_integer(PacketLenOld) and is_binary(Remain) ->
case gen_tcp:recv(ClientSock, 0) of
{ok, B} ->
Bin = <<Remain/binary, B/binary>>,
%% read the packet length
if PacketLenOld =:= 0 andalso erlang:byte_size(Bin) > 2
-> <<PacketLen:16, Remain2/binary>> = Bin;
true -> Remain2 = Bin, PacketLen = PacketLenOld
end,
?DEBUG("packet length ~p", [PacketLen]),
if
erlang:byte_size(Remain2) >= PacketLen
-> {RealData, Next} = split_binary(Remain2, PacketLen),
MainData = decode(RealData),
{ok, MainData, 0, Next};
true -> {continue, PacketLen, Remain2}
end;
{error, closed} ->
?DEBUG("socket closed ~p ~n", [ClientSock]),
{error, closed};
{error, Reason} ->
?ERROR_MSG("socket closed ~p with reason: ~p ~n", [ClientSock, Reason]),
{error, Reason}
end.
翻了翻文档发现实际上在erlang中没有必要这样麻烦
The Length argument is only meaningful when the socket is in raw mode and denotes the number of bytes to read.
If Length = 0, all available bytes are returned. If Length > 0, exactly Length bytes are returned, or an error;
recv(ClientSock) ->
case gen_tcp:recv(ClientSock, 2) of
{ok, PacketLenBin} -> <<PacketLen:16>> = PacketLenBin,
case gen_tcp:recv(ClientSock, PacketLen) of
{ok, RealData} ->
?DEBUG("recv data ~p", [RealData]),
{ok, decode(RealData)};
{error, Reason} ->
?ERROR_MSG("read packet data failed with reason: ~p", [Reason]),
{error, Reason}
end;
{error, Reason} ->
?ERROR_MSG("read packet length failed with reason: ~p", [Reason]),
{error, Reason}
end.
从rabbit_sup模块开始看起:
rabbit_sup模块的start_link是被rabbit app模块的start/2方法所调用的
rabbit.erl文件:
start(normal, []) ->
{ok, SupPid} = rabbit_sup:start_link(),
rabbit_sup.erl文件:
-define(SERVER, ?MODULE).
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
这里的?SERVER和?MODULE是一样的值,都为rabbit_sup 。 READ THE FULL ARTICLE >>
诸多erlang应用都是基于erlang现有的一些application,rabbitmq也不例外,在rabbitmq中,需要的application有sasl、os_mon、mnesia。而rabbitmq启动这些application(包括其自身)的代码写的相当的巧妙:(源码基于rabbitmq 1.7.0)
文件 rabbit.erl
-define(APPS, [os_mon, mnesia, rabbit]).
start() ->
try
ok = prepare(),
ok = rabbit_misc:start_applications(?APPS)
after
%%give the error loggers some time to catch up
timer:sleep(100)
end.
stop() ->
ok = rabbit_misc:stop_applications(?APPS).
文件 rabbit_misc.erl
manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) ->
Iterate(fun (App, Acc) ->
case Do(App) of
ok -> [App | Acc];
{error, {SkipError, _}} -> Acc;
{error, Reason} ->
lists:foreach(Undo, Acc),
throw({error, {ErrorTag, App, Reason}})
end
end, [], Apps),
ok.
start_applications(Apps) ->
manage_applications(fun lists:foldl/3,
fun application:start/1,
fun application:stop/1,
already_started,
cannot_start_application,
Apps).
stop_applications(Apps) ->
manage_applications(fun lists:foldr/3,
fun application:stop/1,
fun application:start/1,
not_started,
cannot_stop_application,
Apps).
顺序启动或者关闭几个application,在失败的情况下首先判断操作失败的原因,如果是已经启动或者已经停止,则跳过;如果是启动失败或者停止失败,则先依次停止或者启动之前已经操作成功的application,之后抛出异常结束进程。
关于是否使用exception风格(个人的说法,也就是非正常的返回值都以抛异常的形式返回)来编码,我产生了一些疑问,经过和同事的一些讨论,我决定做些简单的性能测试。
<?php
/**
* Exception 简单的性能测试
* @author Qingliang.Cn qing.liang.cn@gmail.com
* @created 2009-11-18
* @lastmodified 2009-11-18
*/
define(‘T’, 1000000);
function no_except($a, $b)
{
if (mt_rand(1, 10) > 0){
return $a + $b;
}
}
function except($a, $b)
{
try {
if (mt_rand(1, 10) > 5){ // 0.5的概率抛出异常
return $a + $b;
}else{
throw new Exception(1);
}
}catch (Exception $e){
return $e->getMessage();
}
}
echo "1. with no exception, time is:";
$begin = microtime(true);
for ($i=0; $i< T; $i++)
{
no_except(1, 1);
}
echo microtime(true) - $begin;
echo "\r\n";
echo "2. with exception, time is:";
$begin = microtime(true);
for ($i=0; $i< T; $i++)
{
except(1, 1);
}
echo microtime(true) - $begin;
echo "\r\n";
结果:
100000 (10W)
1. with no exception, time is:3.2554759979248
2. with exception, time is:4.2815051078796
1000000(100W)
1. with no exception, time is:31.89279794693
2. with exception, time is:39.047714948654
上面的测试结果可以看出消耗的时间是相当稳定的,直接的结果是exception比直接return要慢。
继续分析
抛出异常的概率为0.5,也就是说:50w次的异常处理导致了11秒的性能损失。每次exception处理的消耗大概是 20 微秒,这个消耗是相当的小的。 因为一般情况下,web请求的时间都是ms级别的。
同时这里还有两点需要注意:
1. 没有使用异常的时候,代码中的逻辑判断分值必然会加多,也是一定的消耗。
2. 多数的程序exception命中率不会如上面代码中那么高(50%)。
所以在PHP中应用exception是不需要考虑性能问题的。
如有不同的观点,欢迎拍砖和讨论。 email: qing.liang.cn at gmail.com
这几天折腾了一下Windows7,总体的感觉不错。从体验上来说,各方面的设置都和XP类似,即使是有变化也是过渡的非常平稳。唯一感觉不太好的是Windows7的画面感觉不太舒服,看起来非常的累,我的显卡是蓝宝4830的,应该不是卡的问题,舍友安装后也觉得电影的画面看起来有格子的感觉,可能是驱动的问题。
可能是因为我刚换的4核CPU,感觉windows7的操作似乎比xp还要流畅。
注意关闭本地web服务器的keepalive功能,否则可能会出现刚刚修改的代码要隔断时间才能失效的问题。目前只在apache环境下发现这个问题。