概述

GenEvent 是事件处理的通用部分的抽象。

通过 GenEvent ,我们给已有的服务 动态 的添加 事件处理。

GenEevent 和 GenServer 的区别

之前已经介绍了 GenServer ,GenServer 和 GenEvent 的主要区别在于:

  • GenServer 是服务器的抽象,除了封装处理 同步/异步 事件的方法之外,还封装了服务器本身的启动/停止等方法。
  • GenEvent 是事件的抽象,封装了 同步/异步 事件的处理方法,GenEvent 可以绑定到任何服务器上,从而动态的 添加 服务器的处理方法。

基于上述的区别,GenEvent 和 GenServer 的应用场景也不同。

  • GenServer 可以帮助我们快速的创建服务,它类似于一个服务的脚手架,使用 GenServer,构建服务时,只需关注服务本身的业务即可
  • GenEvent 可以用于给现有的服务动态添加处理方法,也可以用于抽象多个服务的共通处理

GenEevent 示例

事件管理器

通过 GenEvent 创建一个事件管理器,将此事件管理器添加到现有进程中,现有进程就有了处理相应事件的能力。

简单示例如下:

  • 接收到 :hello 则返回 :world
  • 接收到 :world 则返回 :hello
  • 接收到 其他消息 则返回 "error msg"
defmodule HelloEvent do
use GenEvent
def handle_event(event, parent) do
case event do
:hello ->
send parent, :world
:world ->
send parent, :hello
_ ->
send parent, "error msg"
end
{:ok, parent}
end
end

测试过程:

# 启动一个空的事件管理器
iex(1)> {:ok, manager} = GenEvent.start_link
{:ok, #PID<0.87.0>}
# 发送 :hello 消息
iex(2)> GenEvent.sync_notify(manager, :hello)
:ok
# 没有任何反应,因为事件管理器中没有任何 handle 来处理消息
iex(3)> flush
:ok
# 给事件管理器增加一个handle,同时将当前进程PID作为事件处理的状态
iex(4)> GenEvent.add_handler(manager, HelloEvent, self())
:ok
# 发送 :hello 消息
iex(5)> GenEvent.sync_notify(manager, :hello)
:ok
# 事件管理器处理了 :hello 消息,并返回 :world 结果
iex(6)> flush
:world
:ok
# 发送 :world 消息
iex(7)> GenEvent.sync_notify(manager, :world)
:ok
# 事件管理器处理了 :world 消息,并返回 :hello 结果
iex(8)> flush
:hello
:ok
# 发送 :test 消息
iex(9)> GenEvent.sync_notify(manager, :test)
:ok
# 事件管理器对于 :hello 和 :world 以外的消息都返回 "error msg"
iex(10)> flush
"error msg"
:ok

上面测试中用的发送消息的方法都是同步方式 sync_notify ,通过异步方式 notify 发送消息也是一样的, GenEvent 的 handle_event 接收同步和异步的消息。

事件流

事件流就是将 GenEvent 的事件转入到流中,这样,就可以通过处理流的方式来处理事件。

比如上面的例子,通过 GenEvent 的 stream ,可以不定义 defmodule HelloEvent 也实现上面的功能。

上述测试过程可以改为如下:

iex(1)> {:ok, manager} = GenEvent.start_link
{:ok, #PID<0.59.0>}
iex(2)> stream = GenEvent.stream(manager)
%GenEvent.Stream{manager: #PID<0.59.0>, timeout: :infinity}
iex(3)>
nil
iex(4)> spawn_link fn ->
...(4)> for x <- stream do
...(4)> case x do
...(4)> :hello -> IO.inspect :world
...(4)> :world -> IO.inspect :hello
...(4)> _ -> IO.inspect "error msg"
...(4)> end
...(4)> end
...(4)> end
#PID<0.71.0>
iex(5)> GenEvent.sync_notify(manager, :hello)
:world
:ok
iex(6)> GenEvent.sync_notify(manager, :world)
:hello
:ok
iex(7)> GenEvent.sync_notify(manager, :test)
"error msg"
:ok

可以看出,我们没有给 GenEvent 绑定任何的 handler,而是在 GenEvent 的事件流中对所有消息进行了处理。

GenEvent 中事件流的特性是 erlang 中所没有的。

总结

除了上面用的 handle_event 和 stream, GenEvent 中还有其他的实用的 Functios 和 Callbacks

具体参见:http://elixir-lang.org/docs/stable/elixir/GenEvent.html

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

elixir 高可用系列(三) GenEvent的更多相关文章

  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 高可用系列(二) GenServer

    概述 如果我们需要管理多个进程,那么,就需要一个专门的 server 来集中监控和控制这些进程的状态,启停等. OTP 平台中的 GenServer 就是对这个 server 通用部分的抽象. 利用 ...

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

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

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

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

  7. Mycat高可用解决方案三(读写分离)

    Mycat高可用解决方案三(读写分离) 一.系统部署规划 名称 IP 主机名称 配置 192.168.199.112 mycat01 2核/2G Mysql主节点 192.168.199.110 my ...

  8. 暑假打工 2 个 月,让我明白了 Keepalived 高可用的三种路由方案

    暑假打工 2 个 月,让我明白了 Keepalived 高可用的三种路由方案 这是悟空的第 158 篇原创文章 原文链接:首发悟空聊架构 官网:www.passjava.cn 你好,我是悟空. 前言 ...

  9. keepalived高可用系列~ keepalived+proxysql

    一 简介:介绍下高可用通用的方案 二 目的:一个中间件提供服务,故障后,另一个中间件提供服务 三 手段: 应用keepalived的vrrp_scripts服务 四 具体配置 global_defs ...

随机推荐

  1. struts2下s:iterator取不出值

    1:问题起因:通过action方法连接数据库取出Arraylist集合,在前台页面遍历显示无数据,用s:debug查看 stack里有值,用了各种方法,包括session传值,但是仍然取不出来. 2: ...

  2. 一个很酷的加载loading效果--IT蓝豹

    一个很酷的加载loading效果,自定义LeafLoadingView实现,LeafLoadingView继承view, 本例子主要由以下几点构成 (1):RotateAnimation实现叶子旋转 ...

  3. position:absolute、float、display:inline-block 区别

    position: absolute会导致元素脱离文档流,被定位的元素等于在文档中不占据任何位置,在另一个层呈现,可以设置z-index.PS的图层效果就是position: absolute. fl ...

  4. oracle 方向及资料

    总结了一下大家的意见,也加了一些个人的看法,Oracle的学习路径,可供参考: 初级阶段: 可以从OCP教材开始,还有文档中的Administrator's Guide.Concepts.Perfor ...

  5. 使用C# WinForm制作 员工打卡项目 -- S2 2.3

    新建一个员工类,存储员工的信息 新建一个List<>集合,并在load事件中实例化三个员工对象 DataGridView绑定数据源,可以显示出数据 点击查询按钮,查询工号等同于输入的数的员 ...

  6. sql语句执行插入后返回ID

    insert into table1(aaa,bbb) values('aaa','bbb') select @@identity

  7. ZT 理解 Android 上的安全性

    理解 Android 上的安全性 http://www.ibm.com/developerworks/cn/xml/x-androidsecurity/ 利用沙箱.应用程序签名和权限增强应用程序安全性 ...

  8. iOS的设备及分辨率、图片命名

    iOS的设备及分辨率(iPhone竖屏/iPad横屏) 设备 分辨率 横宽比 iPhone 3GS.iPod Touch第三代 320 * 480 2 : 3 iPhone 4.iPod Touch第 ...

  9. TF-IDF 相关概念

    概念 TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度. TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级. 词频( ...

  10. USB协议(1)

    今天开始学习USB协议,精挑细选,我决定使用<圈圈教你玩USB>这本书,并且参考网友翻译的<USB2.0中文协议>. 这两本书都可以在ishare.sina.com.cn 即新 ...