跨不同流程使用Elixir ETS
我试图围绕ETS实现一个非常简单的示例,但没有取得多大成功。我想让多个跨不同流程使用Elixir ETS,elixir,ets,Elixir,Ets,我试图围绕ETS实现一个非常简单的示例,但没有取得多大成功。我想让多个worker进程写入ETS表,然后让一个(不同的)读卡器进程定期检索值作为总和。我似乎无法在没有崩溃的情况下插入到表中,而读取器在执行时返回零…这是我的代码,非常感谢收到的任何帮助: 主管模块: defmodule Stackex do use Application @noOfWriters 1 def start(_type, _args) do import Supervisor.Spec, wa
worker
进程写入ETS表,然后让一个(不同的)读卡器进程定期检索值作为总和。我似乎无法在没有崩溃的情况下插入到表中,而读取器在执行时返回零…这是我的代码,非常感谢收到的任何帮助:
主管
模块:
defmodule Stackex do
use Application
@noOfWriters 1
def start(_type, _args) do
import Supervisor.Spec, warn: false
Stackex.Reader.start_link
Stackex.Table.start_link
opts = [strategy: :one_for_one, name: Stackex.Supervisor]
children =
for i <- 1..@noOfWriters do
worker(Stackex.Writer, [i], id: i)
end
Supervisor.start_link(children, opts)
end
end
defmodule Stackex.Writer do
use GenServer
def start_link(id) do
GenServer.start_link(__MODULE__,{id})
end
def init({id}) do
state = %{writer_id: id, value: value}
schedule_work()
{:ok, state}
end
def handle_info(:update, state) do
Stackex.Table.add_kvp(state)
update = %{writer_id: state.writer_id, value: value}
schedule_work()
{:noreply, update}
end
defp value do
:random.seed(:erlang.now())
:random.uniform(10)
end
defp schedule_work() do
Process.send_after(self, :update, 1000)
end
end
defmodule Stackex.Table do
use GenServer
def start_link do
GenServer.start_link(__MODULE__,[], name: __MODULE__)
end
def init do
{:ok, :ets.new(:table, [:set, :named_table])}
end
#Client API
def add_kvp(update) do
GenServer.cast __MODULE__, {:load, update}
end
def get_kvp_sum do
GenServer.call __MODULE__, {:sum}
end
###### Server Callback Functions ########
def handle_cast({:load, update}, state) do
%{writer_id: key, value: value} = update
{:noreply, :ets.insert(:table, {key, value})}
end
#Return total system load
def handle_call({:sum}, _from, state) do
sum = :ets.foldl(fn({{_,v}, acc}) -> v + acc end, 0, :table)
{:reply, sum, state}
end
end
defmodule Stackex.Reader do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init do
schedule_update
{:ok, nil}
end
def handle_info(:update) do
sum = Stackex.Table.get_kvp_sum
IO.puts("Sum #{sum}")
schedule_update
{:noreply, nil}
end
defp schedule_update do
Process.send_after(self, :update, 2000)
end
end
表
模块:
defmodule Stackex do
use Application
@noOfWriters 1
def start(_type, _args) do
import Supervisor.Spec, warn: false
Stackex.Reader.start_link
Stackex.Table.start_link
opts = [strategy: :one_for_one, name: Stackex.Supervisor]
children =
for i <- 1..@noOfWriters do
worker(Stackex.Writer, [i], id: i)
end
Supervisor.start_link(children, opts)
end
end
defmodule Stackex.Writer do
use GenServer
def start_link(id) do
GenServer.start_link(__MODULE__,{id})
end
def init({id}) do
state = %{writer_id: id, value: value}
schedule_work()
{:ok, state}
end
def handle_info(:update, state) do
Stackex.Table.add_kvp(state)
update = %{writer_id: state.writer_id, value: value}
schedule_work()
{:noreply, update}
end
defp value do
:random.seed(:erlang.now())
:random.uniform(10)
end
defp schedule_work() do
Process.send_after(self, :update, 1000)
end
end
defmodule Stackex.Table do
use GenServer
def start_link do
GenServer.start_link(__MODULE__,[], name: __MODULE__)
end
def init do
{:ok, :ets.new(:table, [:set, :named_table])}
end
#Client API
def add_kvp(update) do
GenServer.cast __MODULE__, {:load, update}
end
def get_kvp_sum do
GenServer.call __MODULE__, {:sum}
end
###### Server Callback Functions ########
def handle_cast({:load, update}, state) do
%{writer_id: key, value: value} = update
{:noreply, :ets.insert(:table, {key, value})}
end
#Return total system load
def handle_call({:sum}, _from, state) do
sum = :ets.foldl(fn({{_,v}, acc}) -> v + acc end, 0, :table)
{:reply, sum, state}
end
end
defmodule Stackex.Reader do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init do
schedule_update
{:ok, nil}
end
def handle_info(:update) do
sum = Stackex.Table.get_kvp_sum
IO.puts("Sum #{sum}")
schedule_update
{:noreply, nil}
end
defp schedule_update do
Process.send_after(self, :update, 2000)
end
end
读卡器
模块:
defmodule Stackex do
use Application
@noOfWriters 1
def start(_type, _args) do
import Supervisor.Spec, warn: false
Stackex.Reader.start_link
Stackex.Table.start_link
opts = [strategy: :one_for_one, name: Stackex.Supervisor]
children =
for i <- 1..@noOfWriters do
worker(Stackex.Writer, [i], id: i)
end
Supervisor.start_link(children, opts)
end
end
defmodule Stackex.Writer do
use GenServer
def start_link(id) do
GenServer.start_link(__MODULE__,{id})
end
def init({id}) do
state = %{writer_id: id, value: value}
schedule_work()
{:ok, state}
end
def handle_info(:update, state) do
Stackex.Table.add_kvp(state)
update = %{writer_id: state.writer_id, value: value}
schedule_work()
{:noreply, update}
end
defp value do
:random.seed(:erlang.now())
:random.uniform(10)
end
defp schedule_work() do
Process.send_after(self, :update, 1000)
end
end
defmodule Stackex.Table do
use GenServer
def start_link do
GenServer.start_link(__MODULE__,[], name: __MODULE__)
end
def init do
{:ok, :ets.new(:table, [:set, :named_table])}
end
#Client API
def add_kvp(update) do
GenServer.cast __MODULE__, {:load, update}
end
def get_kvp_sum do
GenServer.call __MODULE__, {:sum}
end
###### Server Callback Functions ########
def handle_cast({:load, update}, state) do
%{writer_id: key, value: value} = update
{:noreply, :ets.insert(:table, {key, value})}
end
#Return total system load
def handle_call({:sum}, _from, state) do
sum = :ets.foldl(fn({{_,v}, acc}) -> v + acc end, 0, :table)
{:reply, sum, state}
end
end
defmodule Stackex.Reader do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init do
schedule_update
{:ok, nil}
end
def handle_info(:update) do
sum = Stackex.Table.get_kvp_sum
IO.puts("Sum #{sum}")
schedule_update
{:noreply, nil}
end
defp schedule_update do
Process.send_after(self, :update, 2000)
end
end
在回答标题中的问题时,当您调用
:ets.new/2
但是根据您发布的代码,您没有多个进程访问您的表。只有一个Stackex.Table
genserver已启动。看起来您甚至不需要它是一个:命名的_表
,因为您只需在状态
变量中传递pid,而对代码的更改很少
看起来您的直接问题是您将错误的变量传递给了add_kvp
方法(state
而不是update
)