再談Erlang代碼熱替換

Erlang一個非常值得稱道的特性就是代碼熱替換(Hot Code Sawpping),我們在調用函數時,通過M:F(A)的方式,可以保證總是加載最新的代碼。

在《Erlang程序設計》中E4部分,通過一個小例子展示了代碼的動態加載,兩個module代碼如下:
a.erl

-module(a).
-compile(export_all).
-import(b, [x/0]).

start(Tag) ->
spawn(fun() -> loop(Tag) end).

loop(Tag) ->
timer:sleep(3000),
Val = x(),
io:format("Vsn1 (~p) b:x() = ~p~n", [Tag, Val]),
loop(Tag).


b.erl

-module(b).
-compile(export_all).

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:

> a:start(one).
Vsn1 (one) b:x() = 1


隨後我們修改a.erl:

-io:format("Vsn1 (~p) b:x() = ~p~n", [Tag, Val]),
+io:format("Vsn2 (~p) b:x() = ~p~n", [Tag, Val]),

然後編譯a.erl:
$ erlc a.erl

當前,在Erlang中只有Vsn1版本的a,回到erlang shell中,加載Vsn2:
> code:load_file(a).

現在在Erlang中有Vsn1和Vsn2兩個版本的a module。
我們在啓動一個新的a process:

> a:start(two).
Vsn2 (two) b:x() =1


好了讓我們再次修改a.erl:

-io:format("Vsn2 (~p) b:x() = ~p~n", [Tag, Val]),
+io:format("Vsn3 (~p) b:x() = ~p~n", [Tag, Val]),

然後編譯a.erl:
$ erlc a.erl

注意:此時Erlang shell中並沒有加載Vsn3版本的代碼,因爲我們沒有使用c(a)的方式編譯加載a module。我們可以測試一下:

>a:start(three).
<0.38.0>
Vsn2 (three) b:x() = 1

毫無疑問,還是Vsn2

接下來我們想加載Vsn3版本的a,回到Erlang shell:
> 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:

> code:purge(a).
true
Vsn2 (three) b:x() = 1
Vsn2 (two) b:x() = 1

返回true,同時Vsn1版本的a process已經被kill了,現在只有Vsn2了。接下來加載我們的Vsn3吧:

> 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成了新版本。
自己動手實驗一下吧!

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.
發佈了10 篇原創文章 · 獲贊 0 · 訪問量 2857
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章