我正在研究我在erlang中的第一个真实项目,但是,为简洁起见,此代码已经过简化。我希望能够在项目运行时将更新版本的文件加载到我的项目远程中。我已经阅读过使用像gen_server
或gen_fsm
这样的行为免费提供的内容。虽然这可能会达到结果,但我想用它来学习如何做到这一点,而不仅仅是完成它。我已经阅读了关于code replacement的文档,以及LYSE关于Hot Code Loving的文章等等,但我找不到任何适用于我正在做的事情,所以这里是基本理念。
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
我只是简单地循环,我可以发送消息upgrade
,它将加载更新版本的代码。
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> c(reloading).
{ok,reloading}
2> Loop = spawn(reloading, loop, []).
<0.39.0>
3> Loop ! hello.
This is a test
hello
此时我将10行更改为io:format("I have changed this!~n"),
4> Loop ! upgrade.
upgrade
5> Loop ! hello.
This is a test
hello
我希望此hello
来电打印I have changed this!
而不是This is a test
。我知道我可以简单地调用c(reloading).
并按照预期的方式工作,但我希望向实际项目发送消息而不是手动更新代码。那么我的断开连接在哪里?我做错了什么,我应该做的是为了加载这段代码?如前所述,为了教育,我正在寻找一种非OTP解决方案。
答案 0 :(得分:22)
为了得到明确的答案,我发布了这个。
使用@rvirding
建议使用code模块,我将其修改为如下所示:
-module(reloading).
-export([loop/0]).
loop() ->
receive
upgrade ->
code:purge(?MODULE),
compile:file(?MODULE),
code:load_file(?MODULE),
?MODULE:loop();
hello ->
io:format("This is a test~n"),
loop();
_ ->
loop()
end.
首先code:purge旧?MODULE
,然后compile:file新文件,最后code:load_file新?MODULE
。
这可以按照我原先的意图运作。
$ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
1> Loop = spawn(reloading, loop, []).
<0.34.0>
2> Loop ! hello.
This is a test
hello
将行更改为io:format("I have changed this!~n"),
3> Loop ! upgrade.
upgrade
4> Loop ! hello.
I have changed this!
hello
答案 1 :(得分:17)
虽然erlang可以处理模块的两个版本,并且使用mod:func(...)
调用函数将始终调用模块的最新版本(如果函数已导出),您仍然需要将新版本的模块加载到Erlang系统。你不能指望它会自动检测到你碰巧在某个地方有一个新版本的模块,找到它,编译它并加载它。
N.B。编译和加载是两回事。因此c(mod).
编译和加载模块,而l(mod).
只加载已编译模块的目标代码(.beam文件)。 Erlang编译器是从模块compile
调用的,它只是编译并生成.beam文件,而代码加载由模块code
处理。
答案 2 :(得分:1)
答案 3 :(得分:0)
在本地编译* .beam,然后将其发送到您的服务器并重新加载,如手册页中所述:
http://erlang.org/documentation/doc-1/reference_manual/code_loading.html#id86381
-module(m).
-export([loop/0]).
loop() ->
receive
code_switch ->
m:loop();
Msg ->
...
loop()
end.