ETS似乎没有存储我的插入内容

时间:2018-08-28 08:58:34

标签: erlang ets

我正在尝试实现一个可以查询/更新一些状态信息的过程(我正在使用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 个答案:

答案 0 :(得分:4)

好的。让我们再次运行代码。

.js

因此,在函数.json的第5行中,您将创建一个ETS表,而在第9、14和17行中,您将再次调用此函数!因此,在收到每条消息(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 除外)之后,您将创建新的ETS表!
让我们看看这些表:

maintain_state/0

在终止您的进程之后,我们应该再次拥有16张表:

void

您有两个选择。您可以使用这样的命名表:

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

或使用table作为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

玩完Erlang的消息传递并了解其功能和概念之后,我真的建议您学习OTP设计原理和gen_server之类的OTP行为,并使用它们代替编写自己的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}}条语句。