elixir 的gen_server
在 erlang的OTP中,gen_server作为通用服务器,是使用频率很高也很好用的一个行为模式,而elixir的底层就是erlang,自然逃不过OTP,包括其中的sup,gen—server等行为模式。
下面就看下在elixir中,它的语法和erlang的gen_server 有什么不同,看elixir的gen_server 是如何写的
一个GenServer实现分为两个部分:客户端API和服务端回调函数。
这两部分可以写在同一个模块里,也可以分开写到两个模块中。
客户端和服务端运行于不同进程,依靠调用客户端函数来与服务端来回传递消息。
方便起见,这里我们将这两部分写在一个模块中。
创建文件registry.ex,包含以下内容:
defmodule GenServerTest do
use GenServer
## Client API
@doc """
Starts the registry.
"""
def start_link() do
GenServer.start_link(__MODULE__, :ok, [])
end
@doc """
Looks up the bucket pid for `name` stored in `server`.
Returns `{:ok, pid}` if the bucket exists, `:error` otherwise.
"""
def lookup(server, name) do
GenServer.call(server, {:lookup, name})
end
@doc """
Ensures there is a bucket associated to the given `name` in `server`.
"""
def create(server, name) do
GenServer.cast(server, {:create, name})
end
## Server Callbacks
def init(:ok) do
{:ok, %{}}
end
def handle_call({:lookup, name}, _from, names) do
{:reply, Map.fetch(names, name), names}
end
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
第一个函数是start_link/0,它传递三个参数启动了一个新的GenServer:
- 实现了服务器回调函数的模块名称。这里的
__MODULE__指的是当前模块 - 初始参数,这里是
:ok - 一组选项列表,比如可以存放服务器的名字。这里用个空列表
你可以向一个GenServer发送两种请求:call和cast。Call 是同步的,
服务器 必须 发送回复给该类请求。Cast 是异步的,服务器 不会 发送回复消息。
再往下的两个方法,lookup/2和create/2,它们用来发送这些请求给服务器。
这两种请求,会被第一个参数所指认的服务器中的handle_call/3和handle_cast/2
函数处理(因此你的服务器回调函数必须包含这两个函数)。GenServer.call/2
和GenServer.cast/2除了指认服务器之外,还告诉服务器它们要发送的请求。
这个请求存储在元组里,这里即{:lookup, name}和{:create, name},
在下面写相应的回调处理函数时会用到。
这个消息元组第一个元素一般是要服务器做的事儿,后面的元素就是该动作的参数。
在服务器这边,我们要实现一系列服务器回调函数来实现服务器的启动、停止以及处理请求等。
回调函数是可选的,我们在这里只实现所关心的那几个。
第一个是init/1回调函数,它接受一个状态参数(你在用户API中调用GenServer.start_link/3中使用的那个),
返回{:ok, state}。这里state是一个新建的map。
我们现在已经可以观察到,GenServer的API中,客户端和服务器之间的界限十分明显。start_link/3在客户端发生。
而其对应的init/1在服务器端运行。
对于call请求,我们在服务器端必须实现handle_call/3回调函数。
参数:接收某请求(那个元组)、请求来源(_from)以及当前服务器状态(names)。handle_call/3函数返回一个{:reply, reply, new_state}元组。
其中,reply是你要回复给客户端的东西,而new_statue是新的服务器状态。
cast请求,我们必须实现一个handle_cast/2回调函数,接受参数:request以及当前服务器状态(names)。
这个函数返回{:noreply, new_state}形式的元组。
这两个回调函数,handle_call/3和handle_cast/2还可以返回其它几种形式的元组。
还有另外几种回调函数,如terminate/2和code_change/3等。
可以参考完整的GenServer文档来学习相关知识。

浙公网安备 33010602011771号