为什么我在 Erlang 中热加载代码后没有得到任何终端输出?
Why dont I get any terminal output after hot code loading in Erlang?
在尝试了解如何使用服务器和热代码加载时,我偶然发现了一个问题,我已将其简化为以下代码:
server.erl
-module(server).
-export([start/0, connect/1]).
start() ->
{ok, Listen} = gen_tcp:listen(8080, [binary, {packet, raw}, {active, true}]),
spawn(?MODULE, connect, [Listen]).
connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
spawn(?MODULE, connect, [Listen]),
loop(Socket).
loop(Socket) ->
receive
{tcp, Socket, Data} ->
io:format("1st version received ~p~n", [Data]),
loop(Socket);
{tcp_closed, Socket} ->
io:format("socket closed~n")
end.
client.erl
-module(client).
-export([request/0]).
request() ->
{ok, Socket} = gen_tcp:connect("localhost", 8080, [{packet, raw}, binary]),
gen_tcp:send(Socket, <<"Hello">>).
启动服务器并发送请求会创建预期的输出。
1> server:start().
<0.62.0>
2> client:request().
ok
1st version received <<"Hello">>
将格式语句更改为“第二版”后,编译并加载代码并执行两个请求(因为当前等待连接的connect/1进程在更改之前产生)结果仍然符合预期.
3> c(server).
{ok,server}
4> client:request().
ok
1st version received <<"Hello">>
5> client:request().
ok
2nd version received <<"Hello">>
但是连续两次编译加载代码后,终端已经没有打印输出了,虽然服务器明显还是运行,因为gen_tcp:connectreturns一个插座。
6> c(server).
{ok,server}
7> c(server).
{ok,server}
8> client:request().
ok
我怀疑此行为与 erlang 使用早于两个版本的代码杀死所有进程有关,但我无法真正理解这里发生的事情。
因为这是教育性的,所以我更想知道为什么这个确切的代码不起作用而不是问题的实际解决方案。
谢谢
我很确定这是两个版本的限制。
如果您想确认这一点,请替换从 spawn(...)
到 spawn_link(...)
的调用——如果进程终止,您的 shell 也会崩溃,您会知道它们已被杀
另一种测试方法是您是否可以替换以下内容:
6> c(server).
{ok,server}
7> c(server).
{ok,server}
8> client:request().
ok
作者:
6> c(server).
{ok,server}
7> client:request().
ok
8> c(server).
{ok,server}
9> client:request().
ok
如果这工作正常,不同之处在于中间的消息允许代码更新到完全限定函数调用的较新代码版本 (Module:Fun(Args)
),从而防止崩溃。
在尝试了解如何使用服务器和热代码加载时,我偶然发现了一个问题,我已将其简化为以下代码:
server.erl
-module(server).
-export([start/0, connect/1]).
start() ->
{ok, Listen} = gen_tcp:listen(8080, [binary, {packet, raw}, {active, true}]),
spawn(?MODULE, connect, [Listen]).
connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
spawn(?MODULE, connect, [Listen]),
loop(Socket).
loop(Socket) ->
receive
{tcp, Socket, Data} ->
io:format("1st version received ~p~n", [Data]),
loop(Socket);
{tcp_closed, Socket} ->
io:format("socket closed~n")
end.
client.erl
-module(client).
-export([request/0]).
request() ->
{ok, Socket} = gen_tcp:connect("localhost", 8080, [{packet, raw}, binary]),
gen_tcp:send(Socket, <<"Hello">>).
启动服务器并发送请求会创建预期的输出。
1> server:start().
<0.62.0>
2> client:request().
ok
1st version received <<"Hello">>
将格式语句更改为“第二版”后,编译并加载代码并执行两个请求(因为当前等待连接的connect/1进程在更改之前产生)结果仍然符合预期.
3> c(server).
{ok,server}
4> client:request().
ok
1st version received <<"Hello">>
5> client:request().
ok
2nd version received <<"Hello">>
但是连续两次编译加载代码后,终端已经没有打印输出了,虽然服务器明显还是运行,因为gen_tcp:connectreturns一个插座。
6> c(server).
{ok,server}
7> c(server).
{ok,server}
8> client:request().
ok
我怀疑此行为与 erlang 使用早于两个版本的代码杀死所有进程有关,但我无法真正理解这里发生的事情。 因为这是教育性的,所以我更想知道为什么这个确切的代码不起作用而不是问题的实际解决方案。
谢谢
我很确定这是两个版本的限制。
如果您想确认这一点,请替换从 spawn(...)
到 spawn_link(...)
的调用——如果进程终止,您的 shell 也会崩溃,您会知道它们已被杀
另一种测试方法是您是否可以替换以下内容:
6> c(server).
{ok,server}
7> c(server).
{ok,server}
8> client:request().
ok
作者:
6> c(server).
{ok,server}
7> client:request().
ok
8> c(server).
{ok,server}
9> client:request().
ok
如果这工作正常,不同之处在于中间的消息允许代码更新到完全限定函数调用的较新代码版本 (Module:Fun(Args)
),从而防止崩溃。