ETS 似乎没有存储我的插入
Posted
技术标签:
【中文标题】ETS 似乎没有存储我的插入【英文标题】:ETS does not seem to store my insert 【发布时间】:2019-02-02 20:27:37 【问题描述】:我正在尝试实现一个可以查询/更新某些状态信息的过程(我正在使用 SMS 服务并希望根据响应存储一些本地数据 - 稍后我将使用数据库,但现在我想使用 ETS,这是我的第一个 Erlang 项目,所以我认为它对学习很有用)。不幸的是,我的插入似乎没有通过,我不明白为什么。这是模块:
-module(st).
-compile(export_all).
maintain_state() ->
Tab = ets:new(state, [set]),
receive
Pid, lookup, Key ->
Pid ! ets:lookup(Tab, Key),
maintain_state();
Pid, update, Key, Handler ->
NewState = Handler(ets:lookup(Tab, Key)),
Status = ets:insert(Tab, NewState),
Pid ! Status, NewState,
maintain_state();
Pid, statelist ->
Pid ! ets:tab2list(Tab),
maintain_state();
kill ->
void
end,
ets:delete(Tab).
start_state_maintainer() ->
Pid = spawn(st, maintain_state, []),
register(state, Pid).
update_state(StateHandler) ->
state ! self(), update, testing, StateHandler,
receive
After ->
After
after 1000 ->
throw("Timeout in update_state")
end.
lookup_state() ->
state ! self(), lookup, testing,
receive
Value ->
Value
after 1000 ->
throw("Timeout in lookup_state")
end.
all_state() ->
state ! self(), statelist,
receive
Value ->
Value
after 1000 ->
throw("Timeout in all_state")
end.
然后我在 erl 会话中加载:
> c(st).
> st:start_state_maintainer().
> st:lookup_state().
[]
> st:update_state(fun (St) -> testing, myval end).
true, testing, myval
> st:all_state().
[]
由于update_state
显示true
我认为插入成功,但表中似乎没有存储任何内容。我做错了什么?
PS:如果整个方法有缺陷,或者您对我的代码有其他评论,我也将不胜感激。
【问题讨论】:
【参考方案1】:好的。让我们再次运行您的代码。
1> c(st). % compile your code
ok,st
% Before doing anything. let's get count of all ETS tables using ets:all/0
2> length(ets:all()).
16 % So the Erlang VM has 16 tables after starting it
3> st:start_state_maintainer().
true
% Let's check count of tables again:
4> length(ets:all()).
17 % Your process has created its own table
5> st:lookup_state().
[]
% Check count of tables again
6> length(ets:all()).
18 % Why????
7> st:update_state(fun (St) -> testing, myval end).
true,testing,myval
8> length(ets:all()).
19
9> st:all_state().
[]
10> length(ets:all()).
20
所以在函数 maintain_state/0
的第 5 行中,您正在创建一个 ETS 表,而在第 9、14 和 17 行中,您再次调用了这个函数!因此,在收到每条消息后(void
除外),您正在创建新的 ETS 表!
让我们看看这些表格:
11> P = whereis(state). % Get process id of 'state' and assign it to P
<0.66.0>
12> Foreach =
fun(Tab) ->
case ets:info(Tab, owner) of
P -> % If owner of table is state's pid
io:format("Table ~p with data ~p~n"
,[Tab, ets:tab2list(Tab)]);
_ ->
ok
end
end.
#Fun<erl_eval.6.118419387>
13> lists:foreach(Foreach, ets:all()).
Table 28691 with data []
Table 24594 with data []
Table 20497 with data [testing,myval]
Table 16400 with data []
ok
杀死你的进程后,我们应该再次拥有 16 个表:
14> exit(P, kill).
true
15> length(ets:all()).
16
你有两个选择。您可以像这样使用命名表:
maintain_state() ->
% With 'named_table' option, we can use the name of table in code:
Tab = ets:new(state, [set, named_table]),
maintain_state2().
maintain_state2() ->
receive
Pid, lookup, Key ->
Pid ! ets:lookup(state, Key), % I used name of table
maintain_state2();
...
或者使用表格作为maintain_state2
的参数:
maintain_state() ->
Tab = ets:new(state, [set]),
maintain_state2(Tab).
maintain_state2(Tab) ->
receive
Pid, lookup, Key ->
Pid ! ets:lookup(Tab, Key),
maintain_state2(Tab);
...
我将代码更改为上述示例之一,结果如下:
1> st:start_state_maintainer().
true
2> st:lookup_state().
[]
3> st:update_state(fun (St) -> testing, myval end).
true,testing,myval
4> st:all_state().
[testing,myval]
5> length(ets:all()).
17
在玩过 Erlang 的消息传递并理解了它的功能和概念之后,我真的建议你学习 OTP 设计原则和 OTP 行为,例如 gen_server 并使用它们,而不是编写自己的 receive ...
和 Pid ! ...
语句。
【讨论】:
啊,我明白了,我应该能够捕捉到那个错误:) 我想也许有一些我不知道的交易系统,我需要提交我的插入。感谢您提供有关 OTP 的建议,我一定会调查的。以上是关于ETS 似乎没有存储我的插入的主要内容,如果未能解决你的问题,请参考以下文章