yb_lin

导航

Erlang代码热替换

Erlang一个非常值得称道的特性就是代码热替换(Hot Code Sawpping),我们在调用函数时,通过M:F(A)的方式,可以保证总是加载最新的代码。

在《Erlang程序设计》中E4部分,通过一个小例子展示了代码的动态加载,两个module代码如下:

1 a.erl
2
3 Erlang代码 -module(a).  
4  -compile(export_all).  
5 -import(b, [x/0]).    
6 start(Tag) ->  
7     spawn(fun() -> loop(Tag) end).  
8       
9 loop(Tag) ->  
10     timer:sleep(3000),       Val = x(),  
11     io:format("Vsn1 (~p) b:x() = ~p~n", [Tag, Val]),       loop(Tag).    
12 -module(a).
13 -compile(export_all).
14 -import(b, [x/0]).
15
16 start(Tag) ->
17     spawn(fun() -> loop(Tag) end).
18    
19 loop(Tag) ->
20     timer:sleep(3000),
21     Val = x(),
22     io:format("Vsn1 (~p) b:x() = ~p~n", [Tag, Val]),
23     loop(Tag).  
24
25
26 b.erl
27
28 Erlang代码 -module(b).  
29 -compile(export_all).  
30  
31 x() -> 1-module(b).
32 -compile(export_all).
33
34 x() -> 1.
35
36

这个例子中是通过c(a), c(b)的方式编译修改后的a.erl 和 b.erl,这里其实是做了两件事:
1,编译module
2,load module
所以我们在这个例子中,可以看到如果我们修改了b的代码,然后在Erlang shell中通过:
c(b). 我们可以立即看到“新”的b module在运行了。

在Erlang中每个Module可以保存2个version,如果再有第三个version加入,那么首先要通过code:purse/1清理先前的版本,随后才可以load新的module。

让我们启动a module:

Erlang代码
1 > a:start(one).  
2 Vsn1 (one) b:x() = 1 
1 > a:start(one).
2 Vsn1 (one) b:x() = 1
现在在Erlang中有Vsn1和Vsn2两个版本的a module。
我们在启动一个新的a process:
Erlang代码
  1. > a:start(two).   
  2. Vsn2 (two) b:x() =1  
> a:start(two).
Vsn2 (two) b:x() =1


好了让我们再次修改a.erl:
Erlang代码
  1. -io:format("Vsn2 (~p) b:x() = ~p~n", [Tag, Val]),   
  2. +io:format("Vsn3 (~p) b:x() = ~p~n", [Tag, Val]),  
-io:format("Vsn2 (~p) b:x() = ~p~n", [Tag, Val]),
+io:format("Vsn3 (~p) b:x() = ~p~n", [Tag, Val]),

然后编译a.erl:
Erlang代码
  1. $ erlc a.erl  
$ erlc a.erl

注意:此时Erlang shell中并没有加载Vsn3版本的代码,因为我们没有使用c(a)的方式编译加载a module。我们可以测试一下:
Erlang代码
  1. >a:start(three).   
  2. <0.38.0>   
  3. Vsn2 (three) b:x() = 1  
>a:start(three).
<0.38.0>
Vsn2 (three) b:x() = 1

毫无疑问,还是Vsn2

接下来我们想加载Vsn3版本的a,回到Erlang shell:
Erlang代码
  1. > code:load_file(a).   
  2. =ERROR REPORT==== 14-Jan-2009::23:16:23 ===   
  3. Loading of /home/litao/erl/a.beam failed: not_purged   
  4. {error,not_purged}   
  5.   
  6. =ERROR REPORT==== 14-Jan-2009::23:16:23 ===   
  7. Module a must be purged before loading  
> code:load_file(a).
=ERROR REPORT==== 14-Jan-2009::23:16:23 ===
Loading of /home/litao/erl/a.beam failed: not_purged
{error,not_purged}

=ERROR REPORT==== 14-Jan-2009::23:16:23 ===
Module a must be purged before loading

oh,产生了一个错误信息,返回{error,not_purged},现在已经有Vsn1,Vsn2两个a module了,这第三个被拒绝了。我们必须调用code:purge/1清除Vsn1:
Erlang代码
  1. > code:purge(a).   
  2. true   
  3. Vsn2 (three) b:x() = 1  
  4. Vsn2 (two) b:x() = 1  
> code:purge(a).
true
Vsn2 (three) b:x() = 1
Vsn2 (two) b:x() = 1

返回true,同时Vsn1版本的a process已经被kill了,现在只有Vsn2了。接下来加载我们的Vsn3吧:
Erlang代码
  1. > code:load_file(a).   
  2. {module,a}   
  3. Vsn2 (two) b:x() = 1  
  4. Vsn2 (three) b:x() = 1  
  5. 8> a:start(five).   
  6. <0.43.0>   
  7. Vsn2 (three) b:x() = 1  
  8. Vsn2 (two) b:x() = 1  
  9. Vsn3 (five) b:x() = 1  
> code:load_file(a).
{module,a}
Vsn2 (two) b:x() = 1
Vsn2 (three) b:x() = 1
8> a:start(five).
<0.43.0>
Vsn2 (three) b:x() = 1
Vsn2 (two) b:x() = 1
Vsn3 (five) b:x() = 1

好了Vsn2成了旧版本,Vsn3成了新版本。
自己动手实验一下吧!

 

posted on 2010-08-18 09:24  废铁  阅读(962)  评论(0编辑  收藏  举报