2012-06-14 86 views
2

我不確定如何調用模塊中的本地函數,以便在代碼更改後將使用最新版本的代碼。Erlang代碼更改和本地函數調用

實施例:

1 -module(test). 
2 
3 -export([start/0, call/1]). 
4 -export([loop/0, add/1]). 
5 
6 start() -> 
7  register(foo, spawn(test, loop, [])). 
8 
9 call(X) -> 
10  foo ! {self(), X}, 
11  receive 
12   Y -> Y 
13 end. 
14 
15 loop() -> 
16  receive 
17   {Pid, Z} -> Pid ! add(Z) 
18  end, 
19  loop(). 
20 
21 add(N) -> 
22  N + 1. 

將要改變的功能是add\1。爲了使用最新版本的功能,撥打add/1(第17行)應該是完全合格的函數調用 {Pid, Z} -> Pid ! ?MODULE:add(Z)。 當我嘗試它,我得到這個:

1> c(test). 
{ok,test} 
2> test:start(). 
true 
3> test:call(1). 
2 

線22變爲N + 2

4> c(test).  
{ok,test} 
5> test:call(1). 
3 

線22再次變爲N + 3

6> c(test).  
{ok,test} 
7> test:call(1). 
** exception error: bad argument 
    in function test:call/1 (test.erl, line 10) 

爲什麼會出現這個錯誤?

回答

3

我相信你需要最終調用loop/0函數的完全限定版本,而不是add/1函數來加載和使用新模塊。代碼加載機制準備一次處理模塊的兩個運行版本,您的示例N+3第三個模塊的加載 - 第一個版本被強制刪除。

嘗試,而不是這個循環:

15 loop() -> 
16  receive 
17   {Pid, Z} -> Pid ! add(Z) 
18  end, 
19  ?MODULE:loop(). 

我已經改變了它重新加載在loop/0的下一次執行的最新版本。

我相信更常見的是使用reload消息或類似的,將明確直接調用主循環,以避免不斷重新加載模塊在每個請求上的開銷。

+0

它的工作原理,謝謝!所以我猜''loop/1'沒有改變,第三次改變後它被擦除了。但是我仍然不明白爲什麼''MODULE:loop()'導致加載一個新版本的'add/1',爲什麼''MODULE:add()'和'loop/1'不一樣? 。 – juro

+0

我認爲這個技巧是'?MODULE:add()'要執行完成,然後該模塊會蒸發。不要忘記,你可能有成千上萬的進程在這個模塊中執行,你不希望從下面的代碼中改變代碼 - 只有那些想改變的代碼。 – sarnold

+2

有關代碼替換的文檔是:Erlang - 編譯和代碼加載http://www.erlang.org/doc/reference_manual/code_loading.html#id83918 – shino