有和没有 shell 的 ETS 的不同行为
Different behaviour of ETS with and without a shell
首先声明我正在学习 erlang。根本不是这里的专家。
在使用 ETS 制作一些示例时,我遇到了一些我不理解的东西(即使在搜索之后)。
我有一个创建 public ETS 的过程
TableID = ets:new(tablename, [public])}
然后我将 TableID 传递给其他进程。当我这样做 运行 将模块形成 shell 时,一切正常。当我 运行 与 erl -noshell -s ... 甚至没有 -noshell 选项完全相同的模块时,它会失败。
我一直收到 error:badarg 就好像 tabled 不存在一样。 ID 正确通过,但 table 实际上表现为私有!
运行ning 模块与 shell 交互或不交互有区别吗?
谢谢
我正在添加我用来尝试调试问题的代码示例。由于它是一个较大的软件(而且它基本上是剥离到骨头上来查找问题),因此可能很难理解。
-record(loop_state, {
commands
}).
start() ->
LoopState = #loop_state{commands = ets:new(commands, [public])},
tcpserver_otp_backend:start(?MODULE, 7000, {?MODULE, loop}, LoopState).
loop(Socket, LoopState = #loop_state{commands = Commands}) ->
case gen_tcp:recv(Socket, 0) of
{ok, Data} ->
% the call below fails, no error generated, AND only in non interactive shell
A = newCommand(Commands, Data),
gen_tcp:send(Socket, A),
loop(Socket, LoopState);
{error, closed} ->
ok
end.
newCommand(CommandTableId, Command) ->
case ets:lookup(CommandTableId,Command) of
[] ->
_A = ets:insert(CommandTableId, {Command, 1}),
<<1, "new", "1">>; % used for testing
_ ->
<<1, "old", "1">> % used for testing
end.
当我删除 "offending command" ets:lookup 时,一切都将再次作为交互式 shell。
问题似乎是您在 start() 函数中创建了 ets table。 ets table 有一个所有者(默认情况下是创建过程),当所有者死亡时,table 将被删除。当您通过将 -s 传递给 erl 从命令行 运行 start/0 函数时,该所有者进程将是 Erlang 内核中的某个内部进程,它是处理启动序列的一部分。无论您是否传递 -noshell,该过程都可能是短暂的,并且会在查找函数有时间执行之前终止,因此当查找最终发生时 table 不再存在。
创建 ets table 的正确位置是在您启动的 gen_server 的 init() 回调函数中。如果它应该是由多个进程访问的 public est table,那么您可能想要创建一个单独的服务器进程,其任务是拥有 table.
首先声明我正在学习 erlang。根本不是这里的专家。 在使用 ETS 制作一些示例时,我遇到了一些我不理解的东西(即使在搜索之后)。
我有一个创建 public ETS 的过程
TableID = ets:new(tablename, [public])}
然后我将 TableID 传递给其他进程。当我这样做 运行 将模块形成 shell 时,一切正常。当我 运行 与 erl -noshell -s ... 甚至没有 -noshell 选项完全相同的模块时,它会失败。 我一直收到 error:badarg 就好像 tabled 不存在一样。 ID 正确通过,但 table 实际上表现为私有!
运行ning 模块与 shell 交互或不交互有区别吗?
谢谢
我正在添加我用来尝试调试问题的代码示例。由于它是一个较大的软件(而且它基本上是剥离到骨头上来查找问题),因此可能很难理解。
-record(loop_state, {
commands
}).
start() ->
LoopState = #loop_state{commands = ets:new(commands, [public])},
tcpserver_otp_backend:start(?MODULE, 7000, {?MODULE, loop}, LoopState).
loop(Socket, LoopState = #loop_state{commands = Commands}) ->
case gen_tcp:recv(Socket, 0) of
{ok, Data} ->
% the call below fails, no error generated, AND only in non interactive shell
A = newCommand(Commands, Data),
gen_tcp:send(Socket, A),
loop(Socket, LoopState);
{error, closed} ->
ok
end.
newCommand(CommandTableId, Command) ->
case ets:lookup(CommandTableId,Command) of
[] ->
_A = ets:insert(CommandTableId, {Command, 1}),
<<1, "new", "1">>; % used for testing
_ ->
<<1, "old", "1">> % used for testing
end.
当我删除 "offending command" ets:lookup 时,一切都将再次作为交互式 shell。
问题似乎是您在 start() 函数中创建了 ets table。 ets table 有一个所有者(默认情况下是创建过程),当所有者死亡时,table 将被删除。当您通过将 -s 传递给 erl 从命令行 运行 start/0 函数时,该所有者进程将是 Erlang 内核中的某个内部进程,它是处理启动序列的一部分。无论您是否传递 -noshell,该过程都可能是短暂的,并且会在查找函数有时间执行之前终止,因此当查找最终发生时 table 不再存在。
创建 ets table 的正确位置是在您启动的 gen_server 的 init() 回调函数中。如果它应该是由多个进程访问的 public est table,那么您可能想要创建一个单独的服务器进程,其任务是拥有 table.