概述

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. Eclipse/MyEclipse怎么设置个性化代码注释模板

    1.打开Eclipse/MyEclipse工具,打开或创建一个Java工程,点击菜单Window->Preferences弹出首选项设置窗口 2.展开左侧Java->Code Style- ...

  2. c# & Fizzler to crawl web page in a certain website domain

    使用fizzler [HtmlAgilityPackExtension]和c#进行网页数据提取:fizzler是HtmlAgilityPack的一个扩展,支持jQuery Selector: 提取数据 ...

  3. gcc相关

    linux操作系统上面开发程序, 光有了gcc 是不行的 它还需要一个   build-essential软件包作用是提供编译程序必须软件包的列表信息 也就是说 编译程序有了这个软件包它才知道 头文件 ...

  4. LinQ 基础

    LinQ全名:Linq to Sql,是一种数据库访问技术 常见的数据库访问技术: 1.ADO.NET 2.Entity Framework  框架 3.LinQ LinQ是高集成化的数据访问类,它会 ...

  5. linux 下文件节点索引

    最近发现一个奇怪的问题,就是一个pyhton 后台的服务一直打印日志文件,在中间我用vim看日志文件,关闭时习惯性的:wq退出,在此之后日志文件就不输出了. 1 对于这个现象我开始认为是python ...

  6. CSS3 中的 rem 值与 px 之间的换算

    想给博客换个主题,到处找找不到满意的,最后发现默认主题 twentytwelve 越看越顺眼,于是就想动手改一下用. 看 CSS 文件的时候发现引入了一个新大小单位:rem,虽然 CSS 文件注释里有 ...

  7. java break语句的三种用法

    1.用于switch语句当中,用于终止语句 2.用于跳出循环,此为不带标签的break语句,相当与goto的作用 e.g while(i<j&&h<k){ if(h< ...

  8. 深刻理解和运用XMLHttpRequest

    本文为转载文章,因见猎心喜,担心失传,故贴此以备不时之需. 原文地址:传送 你真的会使用XMLHttpRequest吗? xmlhttprequest http cors ajax ruoyiqing ...

  9. linux编译curl库的动态库so(转)

    转载请注明出处:帘卷西风的专栏(http://blog.csdn.NET/ljxfblog) curl库是一个很强大的http开源库,c++里面能够很方便的和http服务器交互. 最近项目开始内测,开 ...

  10. POST 和GET传输的最大容量分别是多少?

    get 是通过URL提交数据,因此GET可提交的数据量就跟URL所能达到的最大长度有直接关系.很多文章都说GET方式提交的数据最多只能是1024字节,而 实际上,URL不存在参数上限的问题,HTTP协 ...