elixir - 22 genserver
访问量: 1541
参考:https://elixir-lang.org/getting-started/mix-otp/genserver.html
新建一个 registry.ex文件
efmodule KV.Registry do
use GenServer
def start_link(opts) do
# 这里的__MODULE__ 表示当前的 module
GenServer.start_link(__MODULE__, :ok, opts)
end
def lookup(server,name) do
GenServer.call(server, {:lookup, name})
end
def create(server, name) do
GenServer.cast(server, {:create, name})
end
def init(:ok) do
{:ok , %{}}
end
# call : 是同步的 sync
def handle_call({:lookup,name}, _from, names) do
{:reply, Map.fetch(names, name), names}
end
# cast: 是异步的(async)
def handle_cast({:create, name}, names ) do
if Map.has_key?(names, name) do
{:noreply, names}
else
{:ok, bucket} = KV.Bucket.start_link([])
{:noreply, Map.put(names, name, bucket)}
end
end
end
测试一下 Agent, Process monitor
$ iex -S mix
iex(1)> {:ok, pid} = KV.Bucket.start_link []
{:ok, #PID<0.153.0>}
iex(2)> Process.monitor pid
#Reference<0.1655961756.1033633793.180708>
iex(3)> Agent.stop pid
:ok
iex(4)> flush
{:DOWN, #Reference<0.1655961756.1033633793.180708>, :process, #PID<0.153.0>,
:normal}
:ok
还可以进一步修改 server的实现, 代码如下:
defmodule KV.Registry do
use GenServer
def start_link(opts) do
# 这里的__MODULE__ 表示当前的 module
GenServer.start_link(__MODULE__, :ok, opts)
end
def lookup(server,name) do
GenServer.call(server, {:lookup, name})
end
def create(server, name) do
GenServer.cast(server, {:create, name})
end
def init(:ok) do
names = %{}
refs = %{}
{:ok, {names, refs}}
end
# call : 是同步的 sync
def handle_call({:lookup,name}, _from, state ) do
{names, _} = state
{:reply, Map.fetch(names, name), state}
end
# cast: 是异步的(async)
def handle_cast({:create, name}, {names, refs}) do
if Map.has_key?(names, name) do
{:noreply, {names, refs}}
else
{:ok, pid} = KV.Bucket.start_link([])
ref = Process.monitor(pid)
refs = Map.put(refs, ref, name)
names = Map.put(names, name, pid)
{:noreply, {names, refs}}
end
end
def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do
{name, refs} = Map.pop(refs, ref)
names = Map.delete(names, name)
{:noreply, {names, refs}}
end
def handle_info(_msg, state) do
{:noreply, state}
end
def stop(server) do
GenServer.stop(server)
end
end