Erlang-China

erlang 中文社区

WebMine 编码后记


WebMine 是我对 Erlang + Push + Ajax 架构模式的试验,作为我的第一个真正的 Erlang 程序。记录一点开发心得吧。


[ANN]let’s play! Erlang’s webmine!


九牛二虎之后,erlang的webmine终于配置起来了。

请点击这里访问:http://erlang-china.org:8088/

任何反馈都欢迎,请在此跟帖。

The Erlang version of web mine game was online!

please click here to play, enjoy! (http://erlang-china.org:8088/)

any comment is welcome.


一个简单的列表操作性能测试


Note:首先要了解,Erlang里面的列表,比如 [1,2,3,4],其实是这样的方式来存储 [1,[2,[3,[4]]]],因此在头部插入一个元素,很简单,但是在尾部插入就比较困难了。

闲来对Erlang中的2个列表操作进行了测试,先上代码:

  1. -module(test_list).
  2. -compile(export_all).
  3.  
  4. main() ->
  5. test_concat(),
  6. test_flatten(),
  7. test_append_tail(),
  8. test_append_header().
  9.  
  10. test_concat() ->
  11. statistics(wall_clock),
  12. test_concat(1000000).
  13.  
  14. test_concat(0) ->
  15. {_, Duration} = statistics(wall_clock),
  16. io:format("Concat Duration ~pms~n", [Duration]),
  17. ok;
  18. test_concat(N) ->
  19. "<title>" ++ integer_to_list(N) ++ "</title>",
  20. test_concat(N-1).
  21.  
  22. test_flatten() ->
  23. statistics(wall_clock),
  24. test_flatten(1000000).
  25.  
  26. test_flatten(0) ->
  27. {_, Duration} = statistics(wall_clock),
  28. io:format("Flatten Duration ~pms~n", [Duration]),
  29. ok;
  30. test_flatten(N) ->
  31. lists:flatten(["<title>",integer_to_list(N),"</title>"]),
  32. test_flatten(N-1).
  33.  
  34. test_append_tail() ->
  35. statistics(wall_clock),
  36. test_append_tail(100000).
  37.  
  38. test_append_tail(0) ->
  39. {_, Duration} = statistics(wall_clock),
  40. io:format("Append tail Duration ~pms~n", [Duration]),
  41. ok;
  42. test_append_tail(N) ->
  43. append_last([], 97, 122),
  44. test_append_tail(N-1).
  45.  
  46. append_last(List, N, N) ->
  47. List ++ [N];
  48. append_last(List, Curr, N) ->
  49. append_last(List ++ [Curr], Curr+1, N).
  50.  
  51.  
  52. test_append_header() ->
  53. statistics(wall_clock),
  54. test_append_header(100000).
  55.  
  56. test_append_header(0) ->
  57. {_, Duration} = statistics(wall_clock),
  58. io:format("Append header Duration ~pms~n", [Duration]),
  59. ok;
  60. test_append_header(N) ->
  61. append_header_and_reverse([], 97, 122),
  62. test_append_header(N-1).
  63.  
  64. append_header_and_reverse(List, N, N) ->
  65. lists:reverse([N|List]);
  66. append_header_and_reverse(List, Curr, N) ->
  67. 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. 1> c(test_list).
  2. {ok,test_list}
  3. 2> test_list:main().
  4. Concat Duration 1637ms
  5. Flatten Duration 6743ms
  6. Append tail Duration 2144ms
  7. Append header Duration 624ms
  8. ok
  9. 3> c(test_list, [native]).
  10. {ok,test_list}
  11. 4> test_list:main().
  12. Concat Duration 863ms
  13. Flatten Duration 6084ms
  14. Append tail Duration 1974ms
  15. Append header Duration 362ms
  16. ok

可见,使用 ++ 合并列表,比使用 lists:flatten() 高效;而使用[H|T]再lists:reverse()的方式比 ++ 高效。使用HIPE编译后,++操作和[H|T]操作的性能也得到了较大的提高。

经常在Erlang的程序代码里面看到类似

  1. foo([], List) ->
  2. lists:reverse(List);
  3. foo([H|T], List) ->
  4. ...
  5. foo(T, [H|List])

这样的代码,里面就是使用了头部插入,然后反转列表的方式。


blahblah Ajax误读?


最近一直在搞 webmine 0.2 (快弄完了)接触了一些 server push 和 ajax 的东西。顺便推荐一下,这篇 More on Ajax and server push 可以算是这一技术角落较为全面的分析文章了。

因为之前也参与《Ajax in Action》的翻译(第一部分:重新思考Web应用,正是鄙人所翻)。结合最近的编程感受,渐渐的冒出一个疑惑——Ajax这个名字,是否容易导致误读呢?单就名字而言 Ajax 往往与 Flex/Flash, Applet, XUL 等等这些名字拿来作为对照,似乎两者之间泾渭分明非此即彼。


cean的另类改造及erlang的手动安装


今天试了试 ESDL (相当于 Erlang 的 OpenGL port?) 出现了诡异的 beam_load.c 错误:

=ERROR REPORT==== 17-May-2007::11:43:31 ===
beam/beam_load.c(1097): Error loading module erlyweb:
  use of opcode 125; this emulator supports only up to 115

没见过吧。我也没见过。不过,通过万能的 google 可以知道,这个错误的原因是 erlang beam 的版本不一致导致的。用 r11b 编译的 beam 用在 r10b 上,就会无一例外的报告这个错误。

似乎除了从新下载一个 37.6M 的 r11b 之外,似乎别无他法?

我忽然想起,cean早已升级到 r11b 了。它也在我的机器上躺着呢。何不利用之?于是开始捣鼓。


【ann】cean.erlang-china.org恢复运作


经过努力 cean.erlang-china.org 已经恢复运转。经测试,安装和更新操作执行成功。


遭遇Erlang版的classloader问题


如下的简单代码:

下载: t1.erl
-module(t1).
-
export([test/0]).
test() ->
 
io:format("this is a test~n").

我们做如下的操作:

$> erlc t1.erl
$> erl
1> erlang:function_exported(t1, test, 0).
false
2> t1:test().
this is a test
ok
3> erlang:function_exported(t1, test, 0).
true

第二行的操作 t1:test(). 是成功的。这也从侧面证明了当前路径“.”是在 erl 的 ebin path 之中,而 erlang 会自动的加载这个 module 。

问题在于:第一次调用 erlang:function_exported(t1, test, 0). 返回 false 。第二次调用 erlang:function_exported(t1, test, 0). 又返回了 true 。

这也许说明 erlang 是在第一次调用某个方法时,动态的加载相应的 beam 文件。可是,对于依赖于 erlang:function_exported 方法的代码来说(比如,当我需要根据输入参数调用不同的方法),又如何能预先知道某个 module 是否已经被 load 进入 runtime 了呢?

BIF erlang:module_loaded(Module) 提供了一条线索。可以通过这个方法来判断一个 module 是否已经加载。此外,erlang:load_module(Module, Bin) 也提供了从二进制的字节码加载一个 module 的方法。但是,莫非要我自己动手来写根据一个 name 来搜索 ebin path 并从中 load 一个 module 字节码的方法么?

晕。。。(待解决)


【link】There is a world outside of Ruby on Rails


SlideAware 的 Didier Prophete 在他的 Blog 中讲述了他从 Ruby on Rails 迁移到 Erlang 的过程之中,他的体会。

SlideAware 是一个分享 powerpoint 的标准 web2.0 网站。这个网站起初用 python 搭建,后来换成 ror 的,在遇到性能问题之后,最近迁移到 Erlang 的方案中来,看来他对此次迁移的效果非常满意。

文章从“数据库支持”,“开发环境/调试器”,“社区”这三个方面讲述了 Erlang 的特性,为 RoRer 们进行了一次“迁移示范”。此外 Erlang 还使得以 push 为基础的 realtime interactive 只需要较少的代价就能实现。

…This means we have to handle a lot of tiny requests/responses. This would be almost suicidal in any other language (or you would need to start adding plenty of servers to support any decent number of users). But not quite so in Erlang since the language was designed for this type of workload… It just scales beautifully (and yes, we still need to add extra servers as well to handle a large load, but just not as many…)…

原文链接在这里

BTW. Didier Prophete 文中提到他们 realtime interactive 的实现方式:

…Look at our latest code push for instance. We just introduced the ability to have live review sessions for PowerPoint slides. You basically see other people currently reviewing the same presentation, you can leave real time notes and also have to ability to send quick IM messages. Think about what really happens in the background for a second. Because all of this is real time, every user is constantly going to the server asking “is there any new note/IM message to display” ? Now, we decided to go with a simple polling approach (== no Comet)…

呵呵,和我在上一篇文章中提到的 google way 如出一辙。

看来,英雄的所见,总是略同地。


关于server push,the google way


前一篇webmine 的 blah中提到 ajax + server push 的想法。实做之中突然发现,貌似这个耳熟能详的东西,反而有点不好弄。

大量的server push,都是 cgi/php/perl 等的例子,采用标准的“页面下不完”方式来实现(即,Content-type: multipart/x-mixed-replace),根据我若干年前做的实验,一方面,这对 IE 是不 work 的(不支持这个 content-type ),另一方面,据说页面没下完,浏览器对 javascript 根本不处理(听说过没试过)。而我试图通过 ajax 来调用 server push 的企图,显然在这种状况下,有遭遇撞墙的危险。


Stiff对编程之神们不可思议的采访


初出茅庐,年仅19岁,来自的波兰Stiff对程序界多位传说中的神仙一般的人物(这些鼎鼎大名的名字包括 Linus Torvalds, Dave Thomas, David Heinemeier Hansson, Steve Yegge, Peter Norvig, Guido Van Rossum, Bjarne Stroustrup, James Gosling, Tim Bray)进行了一次不可思议的采访

恕我愚昧,直到今天,我才找到这条发表于2006年10月16日的消息。不过,说不得,象这样的强贴,再老也要转。

btw. 之所以会留意到 Stiff 是因为他也是一个 Erlanger 而且还写了一个很不错 Erlang 教程 Erlang For The Practical Man,在这个教程中,他实现了一个 POP3-RSS gateway 非常值得一看。