关注LAMP|PHP源代码分析|web架构|PHP扩展|Erlang|服务端架构
Erlang
Erlang中日志管理三两话
三 10th
日志系统的重要性就不罗嗦了,直接开始吧。
一、基本概念
在Erlang中,通过两个概念管理错误事情:事件管理器(event manager)和事件处理句柄(event handles)。通常各种错误、警告和消息事件都会有Erlang运行时系统发送给事件管理器。在Erlang中,默认的事情管理器为error logger,其进程名注册为error_logger。默认情况下error_logger把这些事件直接输出到控制台上。 更多 >
list comprehensions与list map性能对比
二 26th
可以使用List comprehensions时不要 使用map或者filter,简单的性能测试对比一下:
第一组,map和list comprehensions对比,代码如下:
%%map方式
-module(map_test).
-export([start/1]).
start(N) ->
statistics(runtime),
erlang:statistics(wall_clock),
lists:map(fun (X) -> X*X end, lists:seq(1, N)),
{_, T1} = erlang:statistics(runtime),
{_, T2} = erlang:statistics(wall_clock),
io:format("total times: ~p, load time: ~p (~p)", [N, T1, T2]).
%%list comprehensions方式
-module(list_comp_test).
-export([start/1]).
start(N) ->
statistics(runtime),
erlang:statistics(wall_clock),
[X*X || X <- lists:seq(1, N)],
{_, T1} = erlang:statistics(runtime),
{_, T2} = erlang:statistics(wall_clock),
io:format("total times: ~p, load time: ~p (~p)", [N, T1, T2]).
测试N为1000000时结果对比:

结果取得是平均值,可以很明显的看出comprehension方式性能要高。
关于filter,则类似。不再作测试。
erlang tcp发包速度测试
二 3rd
这段时间我们的项目遇到广播包的一些性能问题,想起之前看到yufeng老大提到的1s广播40K包的问题,我也想测试测试我们机器的IO能力。
这次仅仅测试发包的能力,采用的是一对一的方式。
测试代码: 更多 >
Erlang中计算16位的MD5字符串
一 18th
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/
Erlang中粘包处理
一 13th
开始时用的传统思路(循环读取):
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.
OTP中supervisor启动过程
一 2nd
从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 。 更多 >
rabbitmq代码摘录(1)
十二 31st
诸多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,之后抛出异常结束进程。
最近评论