gen_event学习

gen_event 是通用的事件处理行为。

描述:

一个实现事件处理功能的行为模块。OTP事件处理模块包括一个通用的事件管理,负责处理可以动态添加、删除的任意数量的事件。用这个模块实现的事件管理器会有一组标准的功能接口,包括跟踪和错误报告功能。它也将融入OTP 监督树中,请参考OTP设计原则了解更多信息。

每个事件处理以回调方式来实现,回调需要导出一组预先设计好的函数,行为函数和回调函数的关系如下:

gen_event module                   Callback module
----------------                   ---------------
%%作为监督树的一部分来创建事件管理器 gen_event:start_link -----> -
%%添加事件 gen_event:add_handler                   gen_event:add_sup_handler -----> Module:init/1
%%事件通知(同步,异步)当事件管理器收到通知后,所有安装的事件均会得到通知。 gen_event:notify gen_event:sync_notify -----> Module:handle_event/2
%%同步调用 gen_event:call -----> Module:handle_call/2 - -----> Module:handle_info/2
%%事件删除 gen_event:delete_handler -----> Module:terminate/2
%%时间管理起中替换现有事件 gen_event:swap_handler gen_event:swap_sup_handler -----> Module1:terminate/2 Module2:init/1
%%返回事件管理中的事件列表 gen_event:which_handlers -----> -
%%停止事件管理器 gen_event:stop -----> Module:terminate/2 - -----> Module:code_change/3

由于每个事件处理模块都是回调模块,一个事件管理器可以动态添加、删除多个回调模块,因此gen_event比其它behaviours对回调模块的错误更tolerant。如果注册的回调函数失败(返回Reason),时间管理器不会失败,它会调用
Module:terminate/2,传参数:{error,{'EXIT',Reason}},其它的事件不会受到任何影响。

注意:时间管理期器会自动捕获exit信号。
gen_event进程可以进入休眠状态,如果回调函数显示返回hibernate。如果服务器预计会空闲较长时间,但是这个特性要慎用。休眠意味着至少有2个垃圾收集(休眠和唤醒不久后)。一个繁忙的事件处理器在处理多个事件间处理的事情不是你想要的。

还需要注意的是,涉及到多个事件处理,一个事件返回hibernate就足够了,因为这回导致事件管理器进入休眠状态。

除非有特殊说明,这个模块中的所有均会失败,若果指定的管理器不存在,或者参数错误。

废话太多了,上手操作吧:

功能:创建一个error_man,注册两个event, terminal_logger和file_logger,用于打印信息到终端和文件。

上代码:
  • 终端event处理
 1 -module(terminal_logger).
 2 -behaviour(gen_event).
 3 
 4 -export([init/1, handle_event/2, terminate/2]).
 5 
 6 init(_Args) ->
 7     {ok, []}.
 8 
 9 handle_event(ErrorMsg, State) ->
10     io:format("***Error*** ~p~n", [ErrorMsg]),
11     {ok, State}.
12 
13 terminate(_Args, _State) ->
14     ok.
  • 文件event处理
 1 -module(file_logger).                                                                              
 2 -behaviour(gen_event).                                                                             
 3                                                                                                                                   
 4 -export([init/1, handle_event/2, terminate/2]).                                                    
 5      
 6 init(File) ->     
 7     case file:open(File, write) of     
 8         {ok, Fd}->     
 9             {ok, Fd};    
10         {_, Reason}->     
11             io:format("open file:~p failed:~p~n", [File, Reason]),    
12             {error, Reason}     
13     end.    
14      
15      
16 handle_event(ErrorMsg, Fd) ->     
17     io:format(Fd, "***Error*** ~p~n", [ErrorMsg]),    
18     {ok, Fd}.    
19      
20 terminate(_Args, Fd) ->     
21     file:close(Fd).  

 

操作过程:

启动:

Eshell V6.0  (abort with ^G)
1> c(terminal_logger).
terminal_logger.erl:2: Warning: undefined callback function code_change/3 (behaviour 'gen_event')
terminal_logger.erl:2: Warning: undefined callback function handle_call/2 (behaviour 'gen_event')
terminal_logger.erl:2: Warning: undefined callback function handle_info/2 (behaviour 'gen_event')
{ok,terminal_logger}

 

2> c(file_logger).
file_logger.erl:2: Warning: undefined callback function code_change/3 (behaviour 'gen_event')
file_logger.erl:2: Warning: undefined callback function handle_call/2 (behaviour 'gen_event')
file_logger.erl:2: Warning: undefined callback function handle_info/2 (behaviour 'gen_event')
{ok,file_logger}

%% 启动时间管理器,本地注册名为:error_man,如果没有注册名,则需要Pid来发送信息。

3> gen_event:start({local,error_man}).
{ok,<0.45.0>}

%%添加终端事件

4> gen_event:add_handler(error_man, terminal_logger,[]).
ok

%%添加文件事件,模拟出错:未传文件名,add_handler第三个参数,将会传到事件处理的init方法中。init必须返回{ok,Stat} 其中State存储在error_man内部中。

5> gen_event:add_handler(error_man, file_logger,[]).    
open file:[] failed:enoent
{error,enoent}


%%添加事件文件为:file.log

6> gen_event:add_handler(error_man, file_logger,["file.log"]).
ok

%%模拟事件"this is a event notify", 期望结果:终端输出信息,同时文件也需要输出信息

7> gen_event:notify(error_man, "this is a event notify").
ok
***Error*** "this is a event notify"

%% 查看文件:

work@nobody-Lenovo:~/test_erl$ tailf file.log
***Error*** "this is a event notify"


%%结果和我们的预期一致

%% 删除终端事件
8> gen_event:delete_handler(error_man, terminal_logger, []).
ok

%%模拟事件"this is a event notify again",预期终端不会打印信息,文件会打印,

9> gen_event:notify(error_man, "this is a event notify again").
ok

%%确认文件:
work@nobody-Lenovo:~/test_erl$ tailf file.log
***Error*** "this is a event notify"
***Error*** "this is a event notify again

Bingo,gen_event 基本用法就介绍到这里

参考:
官方文档:
  1. gen_event官方文档
  2. OTP_Design Principles User'Guide之gen_event(E文)
  3. OTP_Design Principles User'Guide之gen_event(中文)


照样一首歌曲送给大家:佛说万物生


转载于:https://www.cnblogs.com/IT-Nobody/p/3739488.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值