- 浏览: 967659 次
- 性别:
- 来自: 广州
最新评论
-
qingchuwudi:
有用,非常感谢!
erlang进程的优先级 -
zfjdiamond:
你好 这条命令 在那里输入??
你们有yum 我有LuaRocks -
simsunny22:
这个是在linux下运行的吧,在window下怎么运行escr ...
escript的高级特性 -
mozhenghua:
http://www.erlang.org/doc/apps/ ...
mnesia 分布协调的几个细节 -
fxltsbl:
A new record of 108000 HTTP req ...
Haproxy 1.4-dev2: barrier of 100k HTTP req/s crossed
Parameterized modules in Erlang
请参考这篇文章 http://ftp.sunet.se/pub/lang/erlang/workshop/2003/paper/p29-carlsson.pdf
我这里讲述的重点是如何实现的。先看代码:
root@nd-desktop:~/test/m# cat main.erl
% File: main.erl
-module(main).
-export([start/0]).
start() ->
M1 = print:new("Humpty"),
M2 = print:new("Dumpty"),
M1:message("Hello!"),
M2:message("Hi!"),
ok.
root@nd-desktop:~/test/m# cat print.erl
% File: print.erl
-module(print, [Name]).
-export([message/1]).
message(Text) ->
io:fwrite("~s: '~s'~n", [Name, Text]),
ok.
编译运行
root@nd-desktop:~/test/m# erlc *.erl
root@nd-desktop:~/test/m# erl -noshell -s main -s erlang halt
Humpty: 'Hello!'
Dumpty: 'Hi!'
在使用上是模拟面向对象的, 面向对象的同学会感到很亲切。但是erlang如何做到这个魔术的呢?
我们来分析下:
root@nd-desktop:~/test/m# erlc +"'S'" *.erl
root@nd-desktop:~/test/m# cat main.S
{module, main}. %% version = 0
{exports, [{module_info,0},{module_info,1},{start,0}]}.
{attributes, []}.
{labels, 7}.
{function, start, 0, 2}.
{label,1}.
{func_info,{atom,main},{atom,start},0}.
{label,2}.
{allocate_zero,1,0}.
{move,{literal,"Humpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{y,0}}.
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{trim,1,0}.
{move,{literal,"Hi!"},{x,0}}.
{apply,1}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 4}.
{label,3}.
{func_info,{atom,main},{atom,module_info},0}.
{label,4}.
{move,{atom,main},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 6}.
{label,5}.
{func_info,{atom,main},{atom,module_info},1}.
{label,6}.
{move,{x,0},{x,1}}.
{move,{atom,main},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
root@nd-desktop:~/test/m# cat print.S
{module, print}. %% version = 0
{exports, [{instance,1},{message,2},{module_info,0},{module_info,1},{new,1}]}.
{attributes, [{abstract,[true]}]}.
{labels, 11}.
{function, new, 1, 2}.
{label,1}.
{func_info,{atom,print},{atom,new},1}.
{label,2}.
{call_only,1,{f,4}}.
{function, instance, 1, 4}.
{label,3}.
{func_info,{atom,print},{atom,instance},1}.
{label,4}.
{test_heap,3,1}.
{put_tuple,2,{x,1}}.
{put,{atom,print}}.
{put,{x,0}}.
{move,{x,1},{x,0}}.
return.
{function, message, 2, 6}.
{label,5}.
{func_info,{atom,print},{atom,message},2}.
{label,6}.
{test,is_tuple,{f,5},[{x,1}]}.
{test,test_arity,{f,5},[{x,1},2]}.
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}.
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
{move,{literal,"~s: '~s'~n"},{x,0}}.
{call_ext,2,{extfunc,io,fwrite,2}}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 8}.
{label,7}.
{func_info,{atom,print},{atom,module_info},0}.
{label,8}.
{move,{atom,print},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 10}.
{label,9}.
{func_info,{atom,print},{atom,module_info},1}.
{label,10}.
{move,{x,0},{x,1}}.
{move,{atom,print},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
先看
print.S
这个模块导出的函数除了module_info外还有3个导出 new/1, instance/1, 更重要的是 message在源码里面是/1, 但是导出是/2,很奇怪是吗?
我们再看下 new 和 instance 返回一个tuple{print, Arg}.
message函数呢?
{test,is_tuple,{f,5},[{x,1}]}. %% 判断第二个参数是否是tuple
{test,test_arity,{f,5},[{x,1},2]}. %%tuple的个数是不是2
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}. %%取出tuple的第二个参数, 这个就是源码里面的Name模块参数
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
我演示下:
root@nd-desktop:~/test/m# erl
Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.3 (abort with ^G)
1> m(print).
Module print compiled: Date: September 25 2009, Time: 07.23
Compiler options: [{cwd,"/root/test/m"},{outdir,"/root/test/m"}]
Object file: /root/test/m/print.beam
Exports:
instance/1
message/2
module_info/0
module_info/1
new/1
ok
2> print:new(tag1).
{print,tag1}
3> print:instance(tag2).
{print,tag2}
4> print:message("hello", print:new(tag1)).
tag1: 'hello'
ok
main.S 就是这么调用我们的print模块的。
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
压入的参数正是 (Message, print:new(tag)), 然后是apply opcode.
我们看下apply opcode:
OpCase(i_apply): {
Eterm* next;
SWAPOUT;
next = apply(c_p, r(0), x(1), x(2), reg);
SWAPIN;
if (next != NULL) {
r(0) = reg[0];
SET_CP(c_p, I+1);
SET_I(next);
Dispatch();
}
I = handle_error(c_p, I, reg, apply_3);
goto post_error_handling;
}
static Uint*
apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
{
int arity;
Export* ep;
Eterm tmp, this;
/*
* Check the arguments which should be of the form apply(Module,
* Function, Arguments) where Function is an atom and
* Arguments is an arity long list of terms.
*/
if (is_not_atom(function)) {
/*
* No need to test args here -- done below.
*/
error:
p->freason = BADARG;
error2:
reg[0] = module;
reg[1] = function;
reg[2] = args;
return 0;
}
/* The module argument may be either an atom or an abstract module
* (currently implemented using tuples, but this might change).
*/
this = THE_NON_VALUE;
if (is_not_atom(module)) {
Eterm* tp;
if (is_not_tuple(module)) goto error;
tp = tuple_val(module);
if (arityval(tp[0]) < 1) goto error;
this = module;
module = tp[1];
if (is_not_atom(module)) goto error;
}
/*
* Walk down the 3rd parameter of apply (the argument list) and copy
* the parameters to the x registers (reg[]). If the module argument
* was an abstract module, add 1 to the function arity and put the
* module argument in the n+1st x register as a THIS reference.
*/
tmp = args;
arity = 0;
while (is_list(tmp)) {
if (arity < (MAX_REG - 1)) {
reg[arity++] = CAR(list_val(tmp));
tmp = CDR(list_val(tmp));
} else {
p->freason = SYSTEM_LIMIT;
goto error2;
}
}
if (is_not_nil(tmp)) { /* Must be well-formed list */
goto error;
}
if (this != THE_NON_VALUE) {
reg[arity++] = this;
}
...
}
上面的代码就是干我们上面解释的事情的。
结论: 模块参数化完全是个语法糖, 没有任何magic。所以这个特性在hipe下也可以放心大胆用。
请参考这篇文章 http://ftp.sunet.se/pub/lang/erlang/workshop/2003/paper/p29-carlsson.pdf
我这里讲述的重点是如何实现的。先看代码:
root@nd-desktop:~/test/m# cat main.erl
% File: main.erl
-module(main).
-export([start/0]).
start() ->
M1 = print:new("Humpty"),
M2 = print:new("Dumpty"),
M1:message("Hello!"),
M2:message("Hi!"),
ok.
root@nd-desktop:~/test/m# cat print.erl
% File: print.erl
-module(print, [Name]).
-export([message/1]).
message(Text) ->
io:fwrite("~s: '~s'~n", [Name, Text]),
ok.
编译运行
root@nd-desktop:~/test/m# erlc *.erl
root@nd-desktop:~/test/m# erl -noshell -s main -s erlang halt
Humpty: 'Hello!'
Dumpty: 'Hi!'
在使用上是模拟面向对象的, 面向对象的同学会感到很亲切。但是erlang如何做到这个魔术的呢?
我们来分析下:
root@nd-desktop:~/test/m# erlc +"'S'" *.erl
root@nd-desktop:~/test/m# cat main.S
{module, main}. %% version = 0
{exports, [{module_info,0},{module_info,1},{start,0}]}.
{attributes, []}.
{labels, 7}.
{function, start, 0, 2}.
{label,1}.
{func_info,{atom,main},{atom,start},0}.
{label,2}.
{allocate_zero,1,0}.
{move,{literal,"Humpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{y,0}}.
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{trim,1,0}.
{move,{literal,"Hi!"},{x,0}}.
{apply,1}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 4}.
{label,3}.
{func_info,{atom,main},{atom,module_info},0}.
{label,4}.
{move,{atom,main},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 6}.
{label,5}.
{func_info,{atom,main},{atom,module_info},1}.
{label,6}.
{move,{x,0},{x,1}}.
{move,{atom,main},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
root@nd-desktop:~/test/m# cat print.S
{module, print}. %% version = 0
{exports, [{instance,1},{message,2},{module_info,0},{module_info,1},{new,1}]}.
{attributes, [{abstract,[true]}]}.
{labels, 11}.
{function, new, 1, 2}.
{label,1}.
{func_info,{atom,print},{atom,new},1}.
{label,2}.
{call_only,1,{f,4}}.
{function, instance, 1, 4}.
{label,3}.
{func_info,{atom,print},{atom,instance},1}.
{label,4}.
{test_heap,3,1}.
{put_tuple,2,{x,1}}.
{put,{atom,print}}.
{put,{x,0}}.
{move,{x,1},{x,0}}.
return.
{function, message, 2, 6}.
{label,5}.
{func_info,{atom,print},{atom,message},2}.
{label,6}.
{test,is_tuple,{f,5},[{x,1}]}.
{test,test_arity,{f,5},[{x,1},2]}.
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}.
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
{move,{literal,"~s: '~s'~n"},{x,0}}.
{call_ext,2,{extfunc,io,fwrite,2}}.
{move,{atom,ok},{x,0}}.
{deallocate,0}.
return.
{function, module_info, 0, 8}.
{label,7}.
{func_info,{atom,print},{atom,module_info},0}.
{label,8}.
{move,{atom,print},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 10}.
{label,9}.
{func_info,{atom,print},{atom,module_info},1}.
{label,10}.
{move,{x,0},{x,1}}.
{move,{atom,print},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
先看
print.S
这个模块导出的函数除了module_info外还有3个导出 new/1, instance/1, 更重要的是 message在源码里面是/1, 但是导出是/2,很奇怪是吗?
我们再看下 new 和 instance 返回一个tuple{print, Arg}.
message函数呢?
{test,is_tuple,{f,5},[{x,1}]}. %% 判断第二个参数是否是tuple
{test,test_arity,{f,5},[{x,1},2]}. %%tuple的个数是不是2
{allocate_heap,0,4,2}.
{get_tuple_element,{x,1},1,{x,2}}. %%取出tuple的第二个参数, 这个就是源码里面的Name模块参数
{put_list,{x,0},nil,{x,0}}.
{put_list,{x,2},{x,0},{x,1}}.
我演示下:
root@nd-desktop:~/test/m# erl
Erlang R13B02 (erts-5.7.3) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.3 (abort with ^G)
1> m(print).
Module print compiled: Date: September 25 2009, Time: 07.23
Compiler options: [{cwd,"/root/test/m"},{outdir,"/root/test/m"}]
Object file: /root/test/m/print.beam
Exports:
instance/1
message/2
module_info/0
module_info/1
new/1
ok
2> print:new(tag1).
{print,tag1}
3> print:instance(tag2).
{print,tag2}
4> print:message("hello", print:new(tag1)).
tag1: 'hello'
ok
main.S 就是这么调用我们的print模块的。
{move,{literal,"Dumpty"},{x,0}}.
{call_ext,1,{extfunc,print,new,1}}.
{move,{x,0},{x,3}}.
{move,{y,0},{x,1}}.
{move,{atom,message},{x,2}}.
{move,{literal,"Hello!"},{x,0}}.
{move,{x,3},{y,0}}.
{apply,1}.
压入的参数正是 (Message, print:new(tag)), 然后是apply opcode.
我们看下apply opcode:
OpCase(i_apply): {
Eterm* next;
SWAPOUT;
next = apply(c_p, r(0), x(1), x(2), reg);
SWAPIN;
if (next != NULL) {
r(0) = reg[0];
SET_CP(c_p, I+1);
SET_I(next);
Dispatch();
}
I = handle_error(c_p, I, reg, apply_3);
goto post_error_handling;
}
static Uint*
apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
{
int arity;
Export* ep;
Eterm tmp, this;
/*
* Check the arguments which should be of the form apply(Module,
* Function, Arguments) where Function is an atom and
* Arguments is an arity long list of terms.
*/
if (is_not_atom(function)) {
/*
* No need to test args here -- done below.
*/
error:
p->freason = BADARG;
error2:
reg[0] = module;
reg[1] = function;
reg[2] = args;
return 0;
}
/* The module argument may be either an atom or an abstract module
* (currently implemented using tuples, but this might change).
*/
this = THE_NON_VALUE;
if (is_not_atom(module)) {
Eterm* tp;
if (is_not_tuple(module)) goto error;
tp = tuple_val(module);
if (arityval(tp[0]) < 1) goto error;
this = module;
module = tp[1];
if (is_not_atom(module)) goto error;
}
/*
* Walk down the 3rd parameter of apply (the argument list) and copy
* the parameters to the x registers (reg[]). If the module argument
* was an abstract module, add 1 to the function arity and put the
* module argument in the n+1st x register as a THIS reference.
*/
tmp = args;
arity = 0;
while (is_list(tmp)) {
if (arity < (MAX_REG - 1)) {
reg[arity++] = CAR(list_val(tmp));
tmp = CDR(list_val(tmp));
} else {
p->freason = SYSTEM_LIMIT;
goto error2;
}
}
if (is_not_nil(tmp)) { /* Must be well-formed list */
goto error;
}
if (this != THE_NON_VALUE) {
reg[arity++] = this;
}
...
}
上面的代码就是干我们上面解释的事情的。
结论: 模块参数化完全是个语法糖, 没有任何magic。所以这个特性在hipe下也可以放心大胆用。
评论
2 楼
z416177937
2010-08-18
在这儿我知道了,这种方法如何应用,而且是可以应用的。后面具体的解释以后看,貌似有点麻烦。先知其然吧。
1 楼
argan
2009-09-25
哈哈,不错,本来只知其然,现在知道一点所以然了
发表评论
-
OTP R14A今天发布了
2010-06-17 14:36 2608以下是这次发布的亮点,没有太大的性能改进, 主要是修理了很多B ... -
R14A实现了EEP31,添加了binary模块
2010-05-21 15:15 2964Erlang的binary数据结构非常强大,而且偏向底层,在作 ... -
如何查看节点的可用句柄数目和已用句柄数
2010-04-08 03:31 4736很多同学在使用erlang的过程中, 碰到了很奇怪的问题, 后 ... -
获取Erlang系统信息的代码片段
2010-04-06 21:49 3386从lib/megaco/src/tcp/megaco_tcp_ ... -
iolist跟list有什么区别?
2010-04-06 20:30 6421看到erlang-china.org上有个 ... -
erlang:send_after和erlang:start_timer的使用解释
2010-04-06 18:31 8247前段时间arksea 同学提出这个问题, 因为文档里面写的很不 ... -
Latest news from the Erlang/OTP team at Ericsson 2010
2010-04-05 19:23 1927参考Talk http://www.erlang-factor ... -
对try 异常 运行的疑问,为什么出现两种结果
2010-04-05 19:22 2781郎咸武<langxianzhe@163.com> ... -
Erlang ERTS Async基础设施
2010-03-19 00:03 2434其实Erts的Async做的很不错的, 相当的完备, 性能又高 ... -
CloudI 0.0.9 Released, A Cloud as an Interface
2010-03-09 22:32 2419基于Erlang的云平台 看了下代码 质量还是不错的 完成了不 ... -
Memory matters - even in Erlang (再次说明了了解内存如何工作的必要性)
2010-03-09 20:26 3365原文地址:http://www.lshift.net/blog ... -
Some simple examples of using Erlang’s XPath implementation
2010-03-08 23:30 1992原文地址 http://www.lshift.net/blog ... -
lcnt 环境搭建
2010-02-26 16:19 2537抄书:otp_doc_html_R13B04/lib/tool ... -
Erlang强大的代码重构工具 tidier
2010-02-25 16:22 2426Jan 29, 2010 We are very happy ... -
[Feb 24 2010] Erlang/OTP R13B04 has been released
2010-02-25 00:31 1335Erlang/OTP R13B04 has been rele ... -
R13B04 Installation
2010-01-28 10:28 1340R13B04后erlang的源码编译为了考虑移植性,就改变了编 ... -
Running tests
2010-01-19 14:51 1393R13B03以后 OTP的模块加入了大量的测试模块,这些模块都 ... -
R13B04在细化Binary heap
2010-01-14 15:11 1449从github otp的更新日志可以清楚的看到otp R13B ... -
R13B03 binary vheap有助减少binary内存压力
2009-11-29 16:07 1593R13B03 binary vheap有助减少binary内存 ... -
erl_nif 扩展erlang的另外一种方法
2009-11-26 01:02 3131我们知道扩展erl有2种方法, driver和port. 这2 ...
相关推荐
NULL 博文链接:https://langzhe.iteye.com/blog/1123218
Erlang及其应用Erlang及其应用Erlang及其应用
erlang的timer和实现机制 Erlang程序设计
Erlang emulator 实现分析Erlang emulator 实现分析
描述erlang的设计,非常实用,•原书名: Programming Erlang: Software for a Concurrent World
kmp游戏中使用频率较高,所以用erlang代码代码实现,效率还行。
erlang入门电子书 erlang编程 Introducing Erlang,作者Simon.St.Laurent
Erlang 模块模板集合 运行./generate.sh -h以获取帮助选项。
Erlang零成本实现云计算,为初学者提供参考和学习,并为企业建设云提供帮助
erlang 安装包
扩展实现Erlang的全局ets, 来自互联网上一个尚未完成的开源项目。 本人开发完善了差不多所有功能。 欢迎下载使用。
Getopt for Erlang 命令行解析模块,其语法与GNU getopt相似。要求您只需要一个较新的Erlang / OTP版本。 该模块已经过从R13B到20的所有版本的Erlang的测试。 您还需要在系统路径中使用的最新版本。安装要编译模块,...
余锋《erlang零成本实现云计算》--淘宝网核心系统技术专家--2010中国软件技术大会.pdf
erlang25.0 windows版本
牛人写的PPT,主要讲述的是ERLANG的一些特点,案例和应用
erlang otp25 win安装包
Erlang是一个结构化,动态类型编程语言,内建并行计算支持。最初是由爱立信专门为通信应用设计的,比如控制交换机或者变换协议等,因此非常适 合于构建分布式,实时软并行计算系统。 使用Erlang编写出的应用运行时...
, 《Erlang编程指南》可以帮助你:, • 理解Erlang的强大功能及其包含的特殊功能。, • 学习并发背后的概念以及Erlang处理并发的方式。, • 编写高效的Erlang程序并保持代码整洁和良好的可读性。, • 探究Erlang如何...
erlang22最新下载包 erlang22.1.tar.gz erlang22最新下载包 erlang22最新下载包