我刚刚学习ETS
和GenServer
,我尝试在我的应用程序启动时初始化缓存。我很可能错误地设计了这个问题,导致我在下面描述的问题,所以任何反馈都会有帮助。使用GenServer初始化ETS缓存
当应用程序初始化时,:ets
表通过worker
创建。
def start_link do
GenServer.start_link(__MODULE__, :ok)
end
def init(:ok) do
tab = :ets.new(:my_table, [:set, :named_table])
:ets.insert(:my_table, {1, "one"})
{:ok, tab}
end
def lookup(key) do
:ets.lookup(:my_table, key)
end
iex(1)> MyApp.DataTable.lookup(1)
[{1, "one"}]
到目前为止这么好...但现在我想更新该表。所以我添加了一个call
:
def add do
GenServer.call(self(), :add)
end
def handle_call(:add, _from, tab) do
tab = :ets.insert(:my_table, {2, "two"})
{:reply, lookup(2), tab}
end
iex(1)> MyApp.DataTable.add
** (exit) exited in: GenServer.call(#PID<0.157.0>, :add, 5000)
** (EXIT) process attempted to call itself
(elixir) lib/gen_server.ex:598: GenServer.call/3
如果我试图修改call
功能GenServer.call(:my_table, :add)
或GenServer.call(__MODULE__, :add)
,我得到这个错误:** (EXIT) no process
。很明显,我在call
上做错了什么。
所以我尝试直接更新:ets
表:
def add_direct do
:ets.insert(:my_table, {2, "two"})
end
iex(1)> MyApp.DataTable.add_direct
** (ArgumentError) argument error
(stdlib) :ets.insert(:my_table, {2, "two"})
(my_app) lib/my_app/data_table.ex:17:
MyApp.DataTable.add_direct/0
当我运行:ets.all()
,我可以看到:my_table
。所以最后我诉诸试图iex
来更新它:
iex(2)> :ets.insert(:my_table, {2, "two"})
** (ArgumentError) argument error
(stdlib) :ets.insert(:my_table, {2, "two"})
只是为了确保我不完全疯了,我跑这完整性检查,做的工作:
iex(2)> :ets.new(:my_table2, [:set, :named_table])
:my_table2
iex(3)> :ets.insert(:my_table2, {2, "two"})
true
我一定会错误在服务器回调中,只是对模块内部如何工作的基本误解。
很好的解释! 'GenServer.start_link(__ MODULE__,:ok,[name:__MODULE __])'正是我所期待的。这真的教会了我很多。 – jdesilvio