zoukankan      html  css  js  c++  java
  • 再谈Erlang代码热替换

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

    在《Erlang程序设计》中E4部分,通过一个小例子展示了代码的动态加载,两个module代码如下:
    a.erl
    Erlang代码 复制代码 收藏代码
    1. -module(a).   
    2. -compile(export_all).   
    3. -import(b, [x/0]).   
    4.   
    5. start(Tag) ->   
    6.     spawn(fun() -> loop(Tag) end).   
    7.        
    8. loop(Tag) ->   
    9.     timer:sleep(3000),   
    10.     Val = x(),   
    11.     io:format("Vsn1 (~p) b:x() = ~p~n", [Tag, Val]),   
    12.     loop(Tag).     


    b.erl
    Erlang代码 复制代码 收藏代码
    1. -module(b).   
    2. -compile(export_all).   
    3.   
    4. x() -> 1.  


    这个例子中是通过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。
    在Erlang内部,当有新的Module被调用时,旧的Module的Export 函数将被新的Export函数代替,因此当我们实用M:F(A)的方式调用函数时,将调用最新代码。

    让我们启动a module:
    Erlang代码 复制代码 收藏代码
    1. > a:start(one).   
    2. Vsn1 (one) b:x() = 1  


    随后我们修改a.erl:
    Erlang代码 复制代码 收藏代码
    1. -io:format("Vsn1 (~p) b:x() = ~p~n", [Tag, Val]),   
    2. +io:format("Vsn2 (~p) b:x() = ~p~n", [Tag, Val]),  

    然后编译a.erl:
    Erlang代码 复制代码 收藏代码
    1. $ erlc a.erl  

    当前,在Erlang中只有Vsn1版本的a,回到erlang shell中,加载Vsn2:
    Erlang代码 复制代码 收藏代码
    1. > code:load_file(a).  

    现在在Erlang中有Vsn1和Vsn2两个版本的a module。
    我们在启动一个新的a process:
    Erlang代码 复制代码 收藏代码
    1. > a:start(two).   
    2. 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]),  

    然后编译a.erl:
    Erlang代码 复制代码 收藏代码
    1. $ 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  

    毫无疑问,还是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  

    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  

    返回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  

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

    Update:
    code:soft_purge(Module),如果没有process运行旧的Module,则返回true(表明此Module可以被温和的purge);否则返回false。
    可以通过erlang:check_process_code(Pid, Module)检测Process是否运行某个Module的Old version,这个检测不会检测process的运行时,判断当前函数是否为old
    请注意:code:purge 和 code:soft_purge 针对的是old version,如果当前module只有一个version,那么 purge返回false, soft_purge返回true.
  • 相关阅读:
    函数介绍
    Php数组
    数据类型的转换
    Php 输出语句
    php运算符
    php变量
    Php 魔术常量
    HDU 2487 Ugly Windows(暴力)(2008 Asia Regional Beijing)
    codeforces 319B Psychos in a Line(模拟)
    codeforces 301D Yaroslav and Divisors(树状数组)
  • 原文地址:https://www.cnblogs.com/xiayong123/p/3717159.html
Copyright © 2011-2022 走看看