该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-05-22
[quote="AvinDev"]:) Erlang的网络编程是挺方便的,但是每次都自己写Socket也太原始。我现在一般用Joe在robust_server这个教程中提供的tcp_server.erl,OpenPoker里面也是用这个的。 它提供了一种回调的方式来写网络应用程序,比较方便,但是对于报文的缓存操作等还要自己做,这样的代码写多了也不爽。我的想法是写一个类似gen_server这样的东东,来抽象出回调行为,用户开发网络应用,就像使用Mina,Ace那样,实现Encoder,Decoder,MessageHandler就可以了。[/quote]
我大致看过,的确是和ACE的reactor相似,但我目前的应用我感觉用这种方式会更麻烦,我需要的是这种请求/回调的方式: 1、请求包头长度2字节; 2、收到包头长度,解出来,根据长度请求包头; 3、收到包头; 4、解出包头,收其它数据。 以上1-2步gen_tcp已经有实现,如果是自己的协议,前2步也要自己实现,但都比较简单。这种方式的好处是只收需要的数据,用回调方式就比较麻烦,需要记录还要收多少长度,有时收到的数据比实际想要的还长,又得分割,实际代码和复杂度可能更高。 |
|
返回顶楼 | |
发表时间:2007-05-22
以前有人说过,对于超多的TCP短连接,比如HTTP Server,Tomcat之类的,使用线程池和阻塞IO不会比非阻塞IO差。
如果是这样的话,Erlang的多进程方式,性能上应该也有保证。 behaviour,引用某人的原话 引用 正如ErLang 的 behaviour,整个骨架不变,变化部分就是外面传过来的 module, function 实现 (callback)。
echo server我写了个,不过没有测试,发上来,有兴趣可以测一下。这个server是接收到换行符 \n, \r\n 才会echo,因此里面有一坨readline从数据包里面查找换行符。 |
|
返回顶楼 | |
发表时间:2007-05-22
引用 1、请求包头长度2字节;
2、收到包头长度,解出来,根据长度请求包头; 3、收到包头; 4、解出包头,收其它数据。 以上1-2步gen_tcp已经有实现,如果是自己的协议,前2步也要自己实现,但都比较简单。这种方式的好处是只收需要的数据,用回调方式就比较麻烦,需要记录还要收多少长度,有时收到的数据比实际想要的还长,又得分割,实际代码和复杂度可能更高。 呵呵,我觉得既然要用Erlang来写,当然就不会照搬ACE那套。Erlang里面通过包头来取数据包那么方便,为什么要丢掉它。 我觉得大概是这样的方式,简单写下: API: start_link(Host, Port, [binary, {active, true}, {length, 2}]). 启动一个监听的TCP Server,报文包头长度2 init({Socket, Port, ServerPid}) -> io:format("Server started~n"), {ok, #State{}}. handle_receive({Socket, Packet}, State) -> % 这里处理接收到的已经去掉包头的报文 {receive_ok} % 返回一个元组,Server根据这个元组内容执行不同操作 {receive_ok, PacketRemain} % PacketRemain 是剩余的报文,需要等待下次接收后一并处理 {not_complete, Packet} %不完整,等待下次接收 handle_closed(Socket, State) -> ok. 大体是这样子,Encode、Decode还需要抽象处理,不应该直接给一个报文让回调函数来处理。ACE这些是用一个Object来处理回调,Erlang里面传个function就行了。 暂时想到就是那么多 |
|
返回顶楼 | |
发表时间:2007-05-22
原来如此,的确是很方便。我脑子还停留在ACE/twisted上,其它语言里都会尽量避免数据拷贝,erlang里面数据切分、拼接(比如list/binary的组成,分割)会不会影响效率呢?另外binary和list的转换是否影响效率,很多东西还不明白,甚至没看到哪个手册上明确告诉我应该用list还是binary,在学习其它语言时最有用的cookbook,erlang版本的目前也很不完整,感觉缺少指导性的东西。某些东西我能实现出来,但可能不是最优化的实现,最贴近语言风格的实现。
|
|
返回顶楼 | |
发表时间:2007-05-22
嗯,谈到数据拷贝,我也是有你这样的想法,很多高性能程序,都尽可能避免数据拷贝,甚至是内核态到用户态的拷贝,比如LVS那样nb烘烘的东西。
而Erlang,到处充满着数据拷贝,消息发送要拷贝,列表操作也需要。 比如一个列表合并 A = [1,2,3] B = [4,5,6] A ++ B 在命令式语言那里,直接操作一个指针就可以了 1 -> 2 -> 3 4 -> 5 -> 6 1 -> 2 -> 3 -> 4 -> 5 -> 6 但是在Erlang里面,只能这样一步一步来 3 -> 4 -> 5 -> 6 2 -> 3 -> 4 -> 5 -> 6 1 -> 2 -> 3 -> 4 -> 5 -> 6 有一本讲ML语言的书上对这种列表操作进行了详尽的说明。 但是因为存在大量的指针和数据拷贝,不共享,Erlang的GC可以做的相当高效。T1曾经讲述过这个问题。 Cookbook,推荐看 《Program Development Using Erlang - Programming Rules and Conventions》,里面讲解了很多惯用法,有指导性意义。 对于“erlang里面数据切分、拼接(比如list/binary的组成,分割)会不会影响效率呢?另外binary和list的转换是否影响效率”这些问题,我自己是写个小程序来测试效率,比如要测试多个字符合并为一个列表,用 [$a] + [$b] + ... 的效率就比 lists:reverse([$z[$y[...[$a]...]]) 差 |
|
返回顶楼 | |
发表时间:2007-05-22
在含有GC的语言中.由immutable数据的copy操作导致的内存开销,远远小于由于修改内存而增加GC latency的影响. 当然对于大型数据来说,ETS,menisa这样mutable的数据库还是首选.erlang中的有些库函数可能使用了C代码优化过比如说reverse,很可能是内部实现中将head,tail的pointer掉了个,速度当然比++快很多.erlang的document中有专门一章efficiency guide专讲效率问题.虽然说该注意的细节还是要注意,但是我认为,写Erlang程序不要把C++中的效率优先的神经质思维带进来.虽然Erlang适用的领域都有高并发高吞吐的要求.但是Erlang存在的目的就是简化这种需求对程序员的负担.靠你自己手工做优化永远比不上大牛们写的VM和Compiler对你代码的优化.
|
|
返回顶楼 | |
发表时间:2007-05-22
[quote="AvinDev"]echo server我写了个,不过没有测试,发上来,有兴趣可以测一下。这个server是接收到换行符 \n, \r\n 才会echo,因此里面有一坨readline从数据包里面查找换行符。 [/quote]
谢谢。我测试了一下,效率还是不错的,在一台4CPU的服务器上取得了每秒连接1.6万的成绩,在我的双核笔记本上每秒连接数也达到了5000以上。由于受TIME_WAIT影响,没有做更多测试,这个成绩应该已经可以满足一般的应用了。 |
|
返回顶楼 | |
发表时间:2007-05-22
[quote="Trustno1"]在含有GC的语言中.由immutable数据的copy操作导致的内存开销,远远小于由于修改内存而增加GC latency的影响. 当然对于大型数据来说,ETS,menisa这样mutable的数据库还是首选.erlang中的有些库函数可能使用了C代码优化过比如说reverse,很可能是内部实现中将head,tail的pointer掉了个,速度当然比++快很多.erlang的document中有专门一章efficiency guide专讲效率问题.虽然说该注意的细节还是要注意,但是我认为,写Erlang程序不要把C++中的效率优先的神经质思维带进来.虽然Erlang适用的领域都有高并发高吞吐的要求.但是Erlang存在的目的就是简化这种需求对程序员的负担.靠你自己手工做优化永远比不上大牛们写的VM和Compiler对你代码的优化.[/quote]
这种神经质免不了,如果我想把它用在项目中,自然不能在效率上输给C++,因为目前的应用已经因为效率问题部署了C++服务器集群。 手工通过一些技巧来优化总能提高点效率,尽量避免对效率影响较大的操作,还是有好处的,不过这种资料好像不多。 |
|
返回顶楼 | |
发表时间:2007-05-24
[quote="AvinDev"]比如要测试多个字符合并为一个列表,用 [$a] + [$b] + ... 的效率就比 lists:reverse([$z[$y[...[$a]...]]) 差 [/quote]
lists:flatten([$a, $b, "A String", $z]) |
|
返回顶楼 | |
发表时间:2007-05-25
erlang的socket io归根到底还要去走他自己的port机制,粗浅看了看数据复制是少不了的,既然用erlang就没必要再和c++比单机性能了,也很难真正比的过。
我们已经在测试并且准备使用ejabberd,和c++实现的jabber server比起来单机性能是差不少的。但是ejabberd可以很容易的组成多服务器的集群,而且处理能力基本随节点数线形增加,就凭这一点,我就对ejabberd相当有好感了,这也才是erlang真正的优势所在。 |
|
返回顶楼 | |