Erlang Gtalk 讨论群8月份聊天记录
Gtalk 讨论群上面都是比较活跃的,大家的讨论也不乏亮点,现在整理出技术讨论的部分,方便大伙
Erlang: Let’s talk to java
试了一下传说中的 JInterface ,使用 OtpErlang.jar 的整个过程其实非常简单,似乎比 JMS 的程序都简单。
首先,我们要用 java 实现的原始 erlang 程序如下,没错,就是巨简单的 echo ,我们的目标是要把它用 java 来改写,不仅写服务端,也要写客户端。
【转】erlang 网络调优实战
原文网址:erlang网络编程的几个性能调优和注意点
原文作者:coderplay
前些天给echo_server写了个非常简单的连接压力测试程序,
- -module(stress_test).
- -export([start/0, tests/1]).
- start() ->
- tests(12345).
- tests(Port) ->
- io:format("starting~n"),
- spawn(fun() -> test(Port) end),
- spawn(fun() -> test(Port) end),
- spawn(fun() -> test(Port) end),
- spawn(fun() -> test(Port) end).
- test(Port) ->
- case gen_tcp:connect("192.168.0.217", Port, [binary,{packet, 0}]) of
- {ok, _} ->
- test(Port);
- _ ->
- test(Port)
- end.
一开始我的这个stress_test客户端运行在windows上面, echo_server服务器端运行在linux上面。结果接受了1016个连接就停止了. 于是我用ulimit -n 改了服务器端的文件描述符数量为10240. 接着还是如此,折腾了几天,最终还是没有搞明白。
于是就求助于公司的linux编程牛人,结果让我一倒… 客户端没有修改文件描述符个数. windows上得在注册表里面改.
【转】公布 mryufeng 同学的 Erlang 秘笈
原文地址:这里 这里 这里 这里
原文作者:mryufeng
上次说请 mryufeng 同学多写写研究心得,还推说不大爱写长东西。隔不了几天,跑到他的 blog 上一看,乖乖龙的东!整了一大堆秘笈,原来是要藏私!说不得,对于这样同志,只能揪出来示众了。注意,以下内容全部是“海贼版”,未经作者明确同意,请慎入!
为什么没用YAWS?
之前的 webmine (抱歉,现在暂时没法访问)是基于 erlang 自带的 inets httpd 而不是如雷贯耳的 YAWS 。有朋友问我,这是为什么,说来说去好像说不清,索性就 blah 一篇了。
为什么不用 yaws 呢?主要有这么几个原因:
一个简单的列表操作性能测试
Note:首先要了解,Erlang里面的列表,比如 [1,2,3,4],其实是这样的方式来存储 [1,[2,[3,[4]]]],因此在头部插入一个元素,很简单,但是在尾部插入就比较困难了。
闲来对Erlang中的2个列表操作进行了测试,先上代码:
- -module(test_list).
- -compile(export_all).
- main() ->
- test_concat(),
- test_flatten(),
- test_append_tail(),
- test_append_header().
- test_concat() ->
- statistics(wall_clock),
- test_concat(1000000).
- test_concat(0) ->
- {_, Duration} = statistics(wall_clock),
- io:format("Concat Duration ~pms~n", [Duration]),
- ok;
- test_concat(N) ->
- "<title>" ++ integer_to_list(N) ++ "</title>",
- test_concat(N-1).
- test_flatten() ->
- statistics(wall_clock),
- test_flatten(1000000).
- test_flatten(0) ->
- {_, Duration} = statistics(wall_clock),
- io:format("Flatten Duration ~pms~n", [Duration]),
- ok;
- test_flatten(N) ->
- lists:flatten(["<title>",integer_to_list(N),"</title>"]),
- test_flatten(N-1).
- test_append_tail() ->
- statistics(wall_clock),
- test_append_tail(100000).
- test_append_tail(0) ->
- {_, Duration} = statistics(wall_clock),
- io:format("Append tail Duration ~pms~n", [Duration]),
- ok;
- test_append_tail(N) ->
- append_last([], 97, 122),
- test_append_tail(N-1).
- append_last(List, N, N) ->
- List ++ [N];
- append_last(List, Curr, N) ->
- append_last(List ++ [Curr], Curr+1, N).
- test_append_header() ->
- statistics(wall_clock),
- test_append_header(100000).
- test_append_header(0) ->
- {_, Duration} = statistics(wall_clock),
- io:format("Append header Duration ~pms~n", [Duration]),
- ok;
- test_append_header(N) ->
- append_header_and_reverse([], 97, 122),
- test_append_header(N-1).
- append_header_and_reverse(List, N, N) ->
- lists:reverse([N|List]);
- append_header_and_reverse(List, Curr, N) ->
- append_header_and_reverse([Curr|List], Curr+1, N).
test_concat() 和 test_flatten(),测试使用 ++ 构造一个 list,和使用 lists:flatten() 构造list的开销;test_append_tail() 和 test_append_header(), 测试使用 ++ 和 [H|T]再lists:reverse() 方式将大量字符构造成一个列表的开销。
- 1> c(test_list).
- {ok,test_list}
- 2> test_list:main().
- Concat Duration 1637ms
- Flatten Duration 6743ms
- Append tail Duration 2144ms
- Append header Duration 624ms
- ok
- 3> c(test_list, [native]).
- {ok,test_list}
- 4> test_list:main().
- Concat Duration 863ms
- Flatten Duration 6084ms
- Append tail Duration 1974ms
- Append header Duration 362ms
- ok
可见,使用 ++ 合并列表,比使用 lists:flatten() 高效;而使用[H|T]再lists:reverse()的方式比 ++ 高效。使用HIPE编译后,++操作和[H|T]操作的性能也得到了较大的提高。
经常在Erlang的程序代码里面看到类似
- foo([], List) ->
- lists:reverse(List);
- foo([H|T], List) ->
- ...
- foo(T, [H|List])
这样的代码,里面就是使用了头部插入,然后反转列表的方式。
写出正确的尾递归代码
你可能早已耳闻,在 erlang 中,循环变成了递归。
你很可能常常看见这样的代码,并因为它是来自于 erlang 官方的文档 getting start with erlang 而觉得这样的代码,可能就是传说中的尾递归。
- -module(tut1).
- -export([fac/1]).
- fac(1) ->
- 1;
- fac(N) ->
- N * fac(N - 1).
没错,一个函数自己调用自己,这就是递归。但,这真的就是传说中可以通过编译优化得“和循环一样快,没有额外开销”的尾递归么?递归和尾递归,是否存在差异呢?
我们可以做一个试验。
【转】Erlang 里面使用Remote shell
原文地址:avindev.javaeye.com
原文作者:AvinDev
今天无意中发现这个功能。。。
在下载的 getting_started-5.0.1.pdf 那里也有这个topic:《Advanced Shell Usage - Job Control Mode》,不知道为何官方html格式的文档那里消失了。
简单来说是这样,比如节点 foo@192.168.0.2 启动了一个daemon
- erl -name foo@192.168.0.2 -setcookie 123456 -noshell -noinput ...
注:即,无shell,无输入,可以理解为以无界面的方式启动。
注:选项 setcookie 是指定 magic cookie ,这个参数也可以在文件中指定。这是 erlang 的“要么就都没有,要么就全权控制”的安全机制,两个 erlang 的 node 如果需要通讯,必须要有相同的 magic cookie。也就是说,你如果知道目标机器的 magic cookie 你就可以远程管理它。
如果要管理它,可以这样:
- # ./start.sh -name bar@192.168.0.3 -setcookie 123456
- Erlang (BEAM) emulator version 5.5.4 [source] [async-threads:0] [hipe] [kernel-poll:false]
- Eshell V5.5.4 (abort with ^G)
- (bar@192.168.0.3)1>
- User switch command
- --> h
- c [nn] - connect to job
- i [nn] - interrupt job
- k [nn] - kill job
- j - list all jobs
- s - start local shell
- r [node] - start remote shell
- q - quit erlang
- ? | h - this message
- --> j
- 1* {shell,start,[init]}
- --> r 'foo@192.168.0.2'
- --> j
- 1 {shell,start,[init]}
- 2* {'foo@192.168.0.2',shell,start,[]}
- --> c 2
- Eshell V5.5.4 (abort with ^G)
- (foo@192.168.0.2)1> nodes().
- ['bar@192.168.0.3']
比用什么rpc的方便多了
btw:Control+G无法在win下的shell里面使用~
注: Control+G 在 windows 下的 erl 中的确不能用,但在 werl (另一个 shell 界面)中可以照样用,windows 下 werl 的热键与文档保持高度一致。
【转】Erlang 字符编码模块: iconv
原文地址:avindev.javaeye.com
原文作者:AvinDev
在Erlang中,要处理字符串编码的转换,可以使用iconv,目前CEAN的发行版本,ejabberd和iconv模块里面都有iconv的库,但是都无法正常运行(提示版本不兼容),但是在ejabberd的安装包可以使用。经过比较,发现是 erl.exe,erlexec.dll,beam.dll 这三个启动程序的问题,ejabberd 的是 V5.5.2.2,而 CEAN1.2 和ErlangOTP R11B4 都是 V5.5.4,可能两个版本跟iconv的c port不兼容。
下面就以ejabberd的erlang版本来说明:
首先启动port
- 1> iconv:start().
- {ok,<0.30.0>}
- 2> iconv:convert("gbk", "utf-8", "你好").
- "浣犲ソ"
Windows下控制台编码为gbk,这里将“你好”编码为UTF8后输出,显示乱码,可以用io:format解决:
- 3> io:format("~w~n", [iconv:convert("gbk", "utf-8", "你好")]).
- [228,189,160,229,165,189]
- ok
反过来流程是一样的:
- 4> iconv:convert("utf-8", "gbk", [228,189,160,229,165,189]).
- "你好"
要解决在Erlang发行版下使用的问题,估计要重新编译iconv的port。有谁有更好的方法,欢迎提出。
注:貌似 N 多的 c port 代码在 cean 版本中都有问题,上次试验 linux 下的 cean yaws 也出了一个 ddll 的包不兼容的问题。而自己从源代码编译 erlang 又巨慢巨痛苦。苦恼啊。
【转】erlang module pg2
原文地址:avindev.javaeye.com
原文作者:AvinDev
《轻松实现可伸缩性,容错性,和负载平衡的大规模多人在线系统》一文里面对“Erlang的分布式进程组(Distributed Named Process Groups)”大吹特吹,就是说的pg2这个module。文档那里虽然写了支持分布式节点,但是并没有说如何如何,只提供了一个join(Name, Pid)。
看了一下openpoker的源码,原来很简单,对于连接上的node,用 which_groups() 多调用几次就可以同步过来了:
主节点先创建一个Group:
- (foo@localhost)1> pg2:create(group).
- ok
- (foo@localhost)2> pg2:get_members(group).
- []
- (foo@localhost)3> pg2:join(group, self()).
- ok
- (foo@localhost)4> pg2:get_members(group).
- [<0.35.0>]
其他节点先连上主节点,然后调用pg2:which_groups().
- (bar@localhost)1> net_adm:ping('foo@localhost').
- pong
- (bar@localhost)2> pg2:which_groups().
- []
- (bar@localhost)3> pg2:which_groups().
- [group]
- (bar@localhost)4> pg2:join(group, self()).
- ok
已经加入了:
- (foo@localhost)5> pg2:get_members(group).
- [<4835.35.0>,<0.35.0>]
使用就是那么简单。但是在pg2的底层实现上,使用了ets,global等模块,下次继续研究。
注:正如它的名称所暗示的 pg2 可以用于管理成组 process 的场景,如:每一个 game session 是一个 process ,由这些 process 形成一个 group ,那么你可以通过这个 group 获取 session 的数目(eg. 在线人数),即便你的 session counter process 死掉,那么在它被自动恢复的时候,可以连上 group 并从中找回 session 数目。


Recent Comments