概述

如果我们需要管理多个进程,那么,就需要一个专门的 server 来集中监控和控制这些进程的状态,启停等。

OTP 平台中的 GenServer 就是对这个 server 通用部分的抽象。

利用 GenServer 中已经提供的通用操作, 可以很方便的开发出可靠,健壮的程序。

下面首先通过一个示例演示 GenServer 的方便和强大之处,然后再对其进行介绍。

GenServer 示例

这是一个 GenServer 管理多个进程的示例,模拟控制各个进程的启动,停止,以及状态查询。

defmodule ProcessMonitor do
use GenServer #====================================================
# api for clients
#====================================================
# start GenServer
def start(data, opt \\ []) do
GenServer.start_link(__MODULE__, data, opt)
end # add process which is controled by this GenServer
def process_add(server, name) do
GenServer.call(server, {:add, name})
end # get process status
def process_status(server, name) do
GenServer.call(server, {:status, name})
end # start a process by name
def process_start(server, name) do
GenServer.cast(server, {:start, name})
end # stop a process by name
def process_stop(server, name) do
GenServer.cast(server, {:stop, name})
end #====================================================
# callbacks for server
#====================================================
def init(data) do
{:ok, data}
end # handle status message synchronization
def handle_call({:status, name}, _from, data) do
val = Map.get(data, name, nil)
{:reply, val, data}
end # handle add message synchronization
def handle_call({:add, name}, _from, data) do
data = Map.put(data, name, "stopped")
{:reply, name, data}
end # handle start message asynchronization
def handle_cast({:start, name}, data) do
data = Map.put(data, name, "running")
{:noreply, data}
end # handle stop message asynchronization
def handle_cast({:stop, name}, data) do
data = Map.put(data, name, "stopped")
{:noreply, data}
end end

上面代码测试方法如下:

$ iex -S mix
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace] Interactive Elixir (1.2.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, server} = ProcessMonitor.start(Map.new) # 创建 GenServer,并初始化一个 map 用于存储此server管理的 process 信息
{:ok, #PID<0.87.0>}
iex(2)> ProcessMonitor.process_status(server, "process01") # 创建 GenServer 后,默认没有管理任何进程,所以没有 process01 的信息
nil
iex(3)> ProcessMonitor.process_add(server, "process01") # 给 GenServer 增加一个被管理进程 process01
"process01"
iex(4)> ProcessMonitor.process_status(server, "process01") # 新加入的进程默认状态是 stopped,示例代码默认这么实现
"stopped"
iex(5)> ProcessMonitor.process_start(server, "process01") # 启动 process01
:ok
iex(6)> ProcessMonitor.process_status(server, "process01") # process01 状态变为 running
"running"
iex(7)> ProcessMonitor.process_stop(server, "process01") # 停止 process01
:ok
iex(8)> ProcessMonitor.process_status(server, "process01") # process01 状态变为 stopped
"stopped"
iex(9)> ProcessMonitor.process_add(server, "process02") # 再增加一个被管理进程 process02
"process02"
iex(10)> ProcessMonitor.process_start(server, "process02") # 启动 process02
:ok
iex(11)> ProcessMonitor.process_status(server, "process02") # process02 状态变为 running
"running"
iex(12)> ProcessMonitor.process_status(server, "process01") # process01 状态仍然是 stopped,不受 process02 的影响
"stopped"
iex(13)> ProcessMonitor.stop(server) # 停止 GenServer

上面的代码是用 mix 创建工程来运行的,mix 的使用方法可以参见 blog:mix 构建工具

GenServer 通用抽象简介

示例代码使用了 GenServer 中的几个关键函数: init handle_call handle_case

  • init: 这个函数在 GenServer.start_link 时执行,对 start_link 中的参数进行处理
  • handle_call: 这个函数接受同步消息并处理
  • handle_cast: 这个函数接受异步消息并处理

处理这3个常用的函数之外,GenServer 中的函数也不是很多,其他的函数,属性以及每个函数返回的值说明请参见:http://elixir-lang.org/docs/stable/elixir/GenServer.html

在上面的示例中,其实 client 也可以直接调用 GenServer 的 handle_call/handle_cast 来发送同步/异步消息,

我之所以封装了一些 api 给 client 调用,一方面,是为了简化客户端的调用(client 的 api 中参数更加简洁直观),

另一方面,将处理消息的代码和 发送消息的代码分开,便于以后扩展(因为,可能存在多个发送消息的处理都对应同一个消息处理)。

来源:http://blog.iotalabs.io/

elixir 高可用系列(二) GenServer的更多相关文章

  1. elixir 高可用系列 - 目录

    1. elixir 高可用系列(一) Agent 2. elixir 高可用系列(二) GenServer 3. elixir 高可用系列(三) GenEvent 4. elixir 高可用系列(四) ...

  2. elixir 高可用系列(五) Supervisor

    概述 OTP 平台的容错性高,是因为它提供了机制来监控所有 processes 的状态,如果有进程出现异常, 不仅可以及时检测到错误,还可以对 processes 进行重启等操作. 有了 superv ...

  3. elixir 高可用系列(四) Task

    概述 之前学习的 Agent,GenSever以及GenEvent,都是用来管理状态或者处理消息的. 但是在很多时候,我们需要的是执行某个任务,这时如果使用 GenSever 或者 GenEvent, ...

  4. elixir 高可用系列(三) GenEvent

    概述 GenEvent 是事件处理的通用部分的抽象. 通过 GenEvent ,我们给已有的服务 动态 的添加 事件处理. GenEevent 和 GenServer 的区别 之前已经介绍了 GenS ...

  5. elixir 高可用系列(一) Agent

    概述 elixir 本身是一种 immutable 的语言,默认情况下,进程间是不共享任何状态的,进程之间通过消息来交互. 而 Agent 则封装了一种进程间共享状态的方式,通过这种方式,不用显式的写 ...

  6. MySQL高可用系列之MHA(二)

    一.參数说明 MHA提供了一系列配置參数.深入理解每一个參数的详细含义,对优化配置.合理使用MHA非常重要.非常多高可用性也都是通过合理配置一些參数而实现的. MHA包含例如以下配置參数,分别说明例如 ...

  7. (5.8)mysql高可用系列——MySQL中的GTID复制(实践篇)

    一.基于GTID的异步复制(一主一从)无数据/少数据搭建 二.基于GTID的无损半同步复制(一主一从)(mysql5.7)基于大数据量的初始化 正文: [0]概念 [0.5]GTID 复制(mysql ...

  8. Mycat高可用解决方案二(主从复制)

    Mycat高可用解决方案二(主从复制) 系统部署规划 名称 IP 主机名称 用户名/密码 配置 mysql主节点 192.168.199.110 mysql-01 root/hadoop 2核/2G ...

  9. Docker 搭建pxc集群 + haproxy + keepalived 高可用(二)

    上一节我们有了两个分片的pxc集群,这一节我们接着安装haproxy和keepalived的实现集群的高可用 一.先下载haproxy的镜像 [root@localhost ~]# docker pu ...

随机推荐

  1. px,pt,em,rem

    一直对px,pt,em,rem的认识有误区,现整理一下,供参考.之后还得整理下关于dpi相关的知识. px(pixe,像素l):是一个虚拟长度单位,是计算机系统的数字化图像长度单位,如果px要换算成物 ...

  2. CSS盒子模型学习记录3(侧面导航栏)

    学习http://www.blueidea.com/tech/web/2007/4545_2.asp 代码试验 html <!DOCTYPE html PUBLIC "-//W3C// ...

  3. 机器学习(四)--- 从gbdt到xgboost

    gbdt(又称Gradient Boosted Decision Tree/Grdient Boosted Regression Tree),是一种迭代的决策树算法,该算法由多个决策树组成.它最早见于 ...

  4. 为什么 1KB = 1024Byte???群里讨论。

  5. System.DateTime.Now的内容

    ?System.DateTime.Now{2016/10/09 15:19:12}    Date: {2016/10/09 0:00:00}    dateData: 985948826838121 ...

  6. 7.29 H5学习笔记

    常用实体字符小于号  < 大于号  > 和号  & 引号  " 撇号  &apos; 分  ¢ 镑  £ 日元  ¥ 欧元  € 小节  § 版权  © 注册  ...

  7. c++学习笔记——构造函数

    构造函数定义:每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数. 需要注意的几点: 1:构造函数不能被声明为const的,当我们创 ...

  8. position:absolute和float会隐式的改变display类型

    position:absolute和float会隐式的改变display类型,不论之前是什么类型的元素(display:none除外),只要设置了position:absolute或float,都会让 ...

  9. 117 FP页面无法查看

    用户表示117 FP页面无法查看,提示如下错误: 跟进: 1.进入FP服务器可看到以下错误 这个错误的框就表示FP的一个进程报错,自动断掉了,需要重新跑一次EXIT,INIT,PLAN,EXPORT, ...

  10. 【BZOJ1226】学校食堂Dining(状压DP)

    题意:见题面 思路:设dp[i,sta,k]为前i个人已经吃完,从第i人到第i+b[i]人的吃饭状况是sta,前一个吃完的人离i的距离是k(可能为负)的最小值 \[ dp[i+1,sta>> ...