erlang作为一个为电信级别而出现的语言,热更新是其最重要的特性之一

 热代码升级-Erlang允许程序代码在运行系统中被修改。旧代码能被逐步淘汰而后被新代码替换。在此过渡期间,新旧代码是共存的。

下面我们以最典型的gen_server为例子,讲解一下这个BT的功能

 -module(tt13).
-behaviour(gen_server). -export([test/0]).
-export([start_link/0, stop/0, init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -record(state, {cnt}). -define(SERVER, ?MODULE). %%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], [{debug, [trace]}]). test() ->
gen_server:call(?SERVER, test). stop() ->
gen_server:cast(?SERVER, stop). %%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init(_) -> {ok, #state{cnt=1}}.
%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% Description: Handling call messages
handle_call(test, _From, #state{cnt=Cnt} = State) ->
{reply, {ok, Cnt}, State#state{cnt=Cnt+1}}; handle_call(stop, _From, State) ->
{stop, normal, ok, State}; handle_call(_Unrec, _From, State) ->
{reply, {error, invalid_call}, State}. %%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}. %%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%-------------------------------------------------------------------- handle_info(_Info, State) ->
{noreply, State}. %%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%-------------------------------------------------------------------- terminate(_Reason, _State) ->
io:format("hello gen server: terminating~n"). %%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) ->
{ok, State}. %%====================================================================
%%other fun
%%====================================================================

 编译运行结果

 1> c(tt13).
{ok,tt13}
2> tt13:start_link().
{ok,<0.39.0>}
3> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,1} to <0.32.0>, new state {state,2}
{ok,1}
4> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,2} to <0.32.0>, new state {state,3}
{ok,2}
5> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,3} to <0.32.0>, new state {state,4}
{ok,3}

如果修改了函数,可以直接运行

 -module(tt13).
-version("1.1").
-behaviour(gen_server). %...........
%...........省略若干行
%................ handle_call(test, _From, #state{cnt=Cnt} = State) ->
{reply, {ok, Cnt}, State#state{cnt=Cnt*2}}; %...........
%...........省略若干行
%................

 可以看到我们修改了计数的方法,而且修改了版本号,然后我们继续运行

 6> c(tt13).                                    %编译新的代码
{ok,tt13}
7> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,4} to <0.32.0>, new state {state,8}
{ok,4}
8> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,8} to <0.32.0>, new state {state,16}
{ok,8}
9> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,16} to <0.32.0>, new state {state,32}
{ok,16}

 可以看到代码就直接替换了,注意编译的时候会用新的代码替换下一次运行的结果,正在运行还是old code,所以不要编译多次(一般在测试环境先进行热更新测试)。

   如果要替换init/1里面的代码?这个方法肯定是不行的,因为init/1代码只运行一次,比如我要修改state结构体,那要怎么弄呢

 -module(tt13).
-version("2.0").
-behaviour(gen_server). -record(state, {testcheck, cnt}).
%...........
%...........省略若干行
%................ init(_) -> {ok, #state{testcheck='chk', cnt=1}}.
%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% Description: Handling call messages
handle_call(test, _From, #state{cnt=Cnt} = State) ->
{reply, {ok, Cnt}, State#state{cnt=Cnt+1}}; %...........
%...........省略若干行
%................ 26 code_change("1.1", {state, Cnt}, _Extra) ->
27 {ok, {state, chk, Cnt}}; code_change(_OldVsn, State, _Extra) ->
{ok, State}. %...........
%...........省略若干行
%................

  我们修改了state结构体,修改了init/1函数,而且重写了code_change/3,下面我们运行如下

 1 10> compile:file(tt13).          /*编译代码
2 {ok,tt13}
3 11> sys:suspend(tt13).           /*暂停服务
4 ok
5 12> code:purge(tt13).           /*清除旧的代码,如果有运行的化
6 false
7 13> code:load_file(tt13).        /*加载新的代码
8 {module,tt13}
9 14> sys:change_code(tt13,tt13,"1.1",[]).    /*修改state状态
10 ok
11 15> sys:resume(tt13).                /*恢复服务
12 ok
16> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,32} to <0.32.0>, new state {state,chk,64}
{ok,32}
17> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,64} to <0.32.0>, new state {state,chk,128}
{ok,64}
18> tt13:test().
*DBG* tt13 got call test from <0.32.0>
*DBG* tt13 sent {ok,128} to <0.32.0>, new state {state,chk,256}
{ok,128}

  整个替换过程是10-15步,注意这个过程中的tt13服务是hang住的,如果这时候使用服务,会出现timeout,所以一般这5步都是同时执行。

       后面可以看到state状态已经改变

erlang的热更新的更多相关文章

  1. [Erlang10]为什么热更新时,Shell执行2次l(Module)后会把原来用到Module的进程 kill?

    0. 问题引入: -module(hot_code_server). -compile(export_all). start() –> erlang:register(?MODULE, erla ...

  2. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  3. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  5. iOS热更新-8种实现方式

    一.JSPatch 热更新时,从服务器拉去js脚本.理论上可以修改和新建所有的模块,但是不建议这样做. 建议 用来做紧急的小需求和 修复严重的线上bug. 二.lua脚本 比如: wax.热更新时,从 ...

  6. 【.net 深呼吸】程序集的热更新

    当一个程序集被加载使用的时候,出于数据的完整性和安全性考虑,程序集文件(在99.9998%的情况下是.dll文件)会被锁定,如果此时你想更新程序集(实际上是替换dll文件),是不可以操作的,这时你得把 ...

  7. 谁偷了我的热更新?Mono,JIT,iOS

    前言 由于匹夫本人是做游戏开发工作的,所以平时也会加一些玩家的群.而一些困扰玩家的问题,同样也困扰着我们这些手机游戏开发者.这不最近匹夫看自己加的一些群,常常会有人问为啥这个游戏一更新就要重新下载,而 ...

  8. ReactNative 告别CodePush,自建热更新版本升级环境

    微软的CodePush热更新非常难用大家都知道,速度跟被墙了没什么区别. 另外一方面,我们不希望把代码放到别人的服务器.自己写接口更新总归感觉安全一点. so,就来自己搞个React-Native A ...

  9. ReactNative 使用微软的CodePush进行热更新,继续填坑

    1.别被开发环境骗了 在我们开发react native的时候,一键运行工程,js改了,只要cmd+R就可以刷新了.然后会轻易以为真正app上线的时候也是一样,只要app一打开就是最新的. 其实!这是 ...

随机推荐

  1. java中进程与线程的区别

    进程是一个正在运行的应用程序.一个进程包含一个或多个线程.它可以是一段完整的代码或部分程序的动态执行.系统资源分配与调度的基本单位.而线程是CPU调度与运行的基本单位,它是一组指令的集合或是程序的特殊 ...

  2. Vue.js新城之勇者探秘录

    那么我们就继续来聊聊学习Vue的一些方法?以下的学习思路可以供大家作为参考: 1.视频教程带你入门:初学者如果没有MVVM模式的基础学习Vue,可能初期切换思路有比较大的难度,这个时候可以借助视频教程 ...

  3. windows之电脑开机出现 this product is covered by one or more of the following prtents

    电脑开机出现 this product is covered by one or more of the following prtents 有次意外断电后就每次都出现这个提示,然后要等检查完才能进入 ...

  4. hdu4779 组合计数+dp

    提交 题意:给了n*m的网格,然后有p个重型的防御塔,能承受1次攻击,q个轻型防御塔不能接受任何攻击,然后每个防御搭会攻击他所在的行和所在的列,最后求在这个网格上放至少一个防御塔的方案数, 我们枚举 ...

  5. angular4实战开发问题——ngclass不起作用

    由于路由机制会导致页面不刷新. 在项目中,很多都是使用click做的路由跳转.ngclass有时候会不起作用, 这个时候我是很盲目的,一开始在考虑是不是书写的问题.ngclass需要有特定的格式?第一 ...

  6. python __str__() 和 __repr__()是干啥的

    1. 没定义__str__() print的时候得不到自己想要的东西 类默认转化的字符串基本没有我们想要的一些东西,仅仅包含了类的名称以及实例的 ID (理解为 Python 对象的内存地址即可).虽 ...

  7. 2019/4/15 wen 正则表达式

  8. 自制操作系统Antz(13) 显示图片

    显示图片只是在多媒体课上看着bmp格式图片的突发奇想,然后就实现在了我自己的操作系统 Antz系统更新地址 Linux内核源码分析地址 Github项目地址 效果图: 显示图片的原理 在之前显卡操作时 ...

  9. 如何使用postman传数组数据

    如何使用postman传数组数据 在我们做api接口数据调试的时候,大部分是会用到postman的,一般请求数据的参数都是字符串,但是特殊情况下我们是需要传一个数组数据的,那么为了实现这种需求,究竟该 ...

  10. The History of spring

    Spring的出现  Spring最早出现对早期J2EE规范复杂性的回应 .虽然有些人一直认为Java EE和Spring处于竞争中,但Spring实际上是对Java EE的补充.Spring编程模型 ...