• 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:

    1. 实现了服务器回调函数的模块名称。这里的__MODULE__指的是当前模块
    2. 初始参数,这里是:ok
    3. 一组选项列表,比如可以存放服务器的名字。这里用个空列表

    你可以向一个GenServer发送两种请求:callcastCall 是同步的,
    服务器 必须 发送回复给该类请求。Cast 是异步的,服务器 不会 发送回复消息。

    再往下的两个方法,lookup/2create/2,它们用来发送这些请求给服务器。
    这两种请求,会被第一个参数所指认的服务器中的handle_call/3handle_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/3handle_cast/2还可以返回其它几种形式的元组。
    还有另外几种回调函数,如terminate/2code_change/3等。
    可以参考完整的GenServer文档来学习相关知识。

  • 相关阅读:
    JavaScript之判断参数的数值的详细类型
    JavaScript之不规则Table转化为可定点索引td节点的网格矩阵【插件】
    JavaScript之从浏览器一键获取教务处个人课程信息【插件】
    Linux之搭建远程数据库MySQL[Ubuntu:全过程]
    数据库之MySQL ERROR 1698 (28000) 错误:Access denied for user 'root'@'localhost'" error【摘抄】
    Linux之常用命令【service】
    Linux之激活超级用户
    计算机网络之互联网|因特网|万维网|HTTP|HTML之间的关系辨析
    [转] Linux Shell 文本处理工具集锦
    可读写的缓冲设计表现
  • 原文地址:https://www.cnblogs.com/unqiang/p/16356131.html
Copyright © 2020-2023  润新知