zoukankan      html  css  js  c++  java
  • Erlang--热更新

      热更新是erlang的一个重要特性:当程序调用M:F(A),总是调用的M:F的最新的编译过的载入的版本。

    • 一个简单的例子如下:
     1 -module(area_server).
     2 %%%================================EXPORT================================
     3 -export([rpc/2, loop/0, start/0, area/2]).
     4 
     5 
     6 %%%============================EXPORT FUNC================================
     7 start() ->
     8     spawn(area_server, loop, []).
     9 
    10 area(Pid, Request) ->
    11     rpc(Pid, Request).
    12 
    13 rpc(Pid, Request) ->
    14     Pid ! {self(), Request},
    15     receive
    16         Response ->
    17             Response
    18     end.
    19 
    20 loop() ->
    21     receive
    22         {From, {rectangle, Width, Height}} ->
    23             From ! Width * Height,
    24             loop();
    25         {From, {circlr, R}} ->
    26             From ! 3.14 * R * R,
    27             loop()
    28     end.

      1.编译area_server模块(不是在shell使用c()函数,工程中采用erl -make命令和emakefile进行编译,后续将会增加一遍博文说明工程),然后启动工程,在shell里面分别执行命令及结果如下:

    1 (test_erlang@WIN-12F3B5SEKIH)1> Pid = area_server:start().
    2 <0.39.0>
    3 (test_erlang@WIN-12F3B5SEKIH)2> area_server:area(Pid, {rectangle, 1, 1}).
    4 1

      2.然后修改area_server模块,在area_server:rpc中添加一句打印:

    1 %% TODO delete
    2     io:format("~n------------------~p:~p-----------------~n", [?FILE, ?LINE]),
    3     io:format("rpc = ~p~n", [rpc]),
    4     io:format("-----------------------------------------------------------------~n"),

      3.重新编译后,在shell中执行area_server:area(Pid, {rectangle, 1, 1}).,结果如下:

    1 (test_erlang@WIN-12F3B5SEKIH)3> area_server:area(Pid, {rectangle, 1, 1}).
    2 1

      4.发现没有新增的打印,原因:编译新的模块后需要再主动加载,使用code:load_file命令后如下:

    1 (test_erlang@WIN-12F3B5SEKIH)4> code:load_file(area_server). 
    2 {module,area_server}
    3 (test_erlang@WIN-12F3B5SEKIH)5> area_server:area(Pid, {rectangle, 1, 1}).
    4 
    5 ------------------"src/area_server.erl":29-----------------
    6 rpc = rpc
    7 -----------------------------------------------------------------
    8 1

      主动加载后才会调用编译的新的模块。

    • erlang热加载的实现原理:
    1. erlang的热更新由code_server.erl模块管理,采用一个private ets table管理代码,每个模块保留两个不能状态的代码:old 和 current
    2. 代码状态的切换:
      1. 当模块M第一次加载时,状态为current
      2. 修改M,编译并重新加载后,之前的current代码状态转变为old,新加载的代码状态为current。以后第一次调用该模块的代码将采用current状态的代码,old状态的代码还会被之前的进程通过local call 所调用
      3. 当再一次修改M,编译并重新加载后,同样的current的状态的代码变为old,而之前的old代码将被干掉,从而使用之前的old状态的进程会被kill

          接着上面的例子看:把打印去掉,重新编译加载,shell中代码如下:

    1 (test_erlang@WIN-12F3B5SEKIH)6> code:load_file(area_server).             
    2 {error,not_purged}
    3 (test_erlang@WIN-12F3B5SEKIH)7> 
    4 =ERROR REPORT==== 10-Jan-2016::01:00:53 ===
    5 Loading of f:/code_play/test_erlang/code/test_code/.ebin/area_server.beam failed: not_purged

          直接使用code:load_file(area_server)会出现错误,因为已经存在装备为old的代码,可以先使用code:purge()清除old状态代码,然后使用code:load_file(area_server),或者直接使用l(area_server),因为l(M)的实现就是上面两句:

    1 %% l(Mod)
    2 %%  Reload module Mod from file of same name
    3 -spec l(Module) -> code:load_ret() when
    4       Module :: module().
    5 
    6 l(Mod) ->
    7     code:purge(Mod),
    8     code:load_file(Mod).

          在shell中执行l(area_server),再调用area_server:start(Pid, {rectangle, 1, 1}),会出现shell“死机”的情况:

    1 (test_erlang@WIN-12F3B5SEKIH)8> l(area_server).
    2 {module,area_server}
    3 (test_erlang@WIN-12F3B5SEKIH)9> area_server:area(Pid, {rectangle, 1, 1}).

                     shell中执行到第3行后,shell就没有反应了,这是因为:Pid这个进程已经被kill了,area函数一直阻塞在receive处。(tip:这种情况可以通过ctrl+G进入user switch command,利用s命令重启一个新的shell).

  • 相关阅读:
    POJ 1691 Painting a Board(状态压缩DP)
    POJ 1946 Cow Cycling(抽象背包, 多阶段DP)
    Leetcode: Best Time to Buy and Sell Stock I, II
    Leetcode: Valid Palindrome
    POJ 1946 Cow Cycling
    POJ 1661 Help Jimmy(递推DP)
    POJ 1160 Post Office(区间DP)
    POJ 2486 apple tree
    Android播放器框架分析之AwesomePlaye
    【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位...
  • 原文地址:https://www.cnblogs.com/joh-n-zhang/p/5117010.html
Copyright © 2011-2022 走看看