非常教程

Erlang 20参考手册

stdlib/gen_event

gen_event

模块

gen_event

模块摘要

一般事件处理行为。

描述

此行为模块提供事件处理功能。它由一个通用事件管理器进程组成,其中包含动态添加和删除的任意数量的事件处理程序。

使用此模块实现的事件管理器具有一组标准的接口函数,并包含用于跟踪和错误报告的功能。它也适合于OTP监督树。有关更多信息,请参阅OTP Design Principles

每个事件处理程序都被实现为一个回调模块,用于导出一组预定义的函数。行为函数和回调函数之间的关系如下所示:

gen_event module                   Callback module
----------------                   ---------------
gen_event:start
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比其他行为更容忍回调模块错误。 如果安装的事件处理程序的回调函数由于Reason而失败,或者返回错误的Term值,则事件管理器不会失败。 它通过调用callback函数Module:terminate / 2,分别给出参数{error,{'EXIT',Reason}}或{error,Term}来删除事件处理程序。 其他事件处理程序不受影响。

一个gen_event进程处理系统消息,如下所述sys(3)。该sys模块可用于调试事件管理器。

请注意,事件管理器自动捕获退出信号。

gen_event过程可以进入休眠状态(见erlang:hibernate/3),如果处理模块中的回调函数指定hibernate其返回值。如果服务器预计长时间处于空闲状态,这可能很有用。但是,请谨慎使用此功能,因为休眠意味着至少有两个垃圾回收(休眠时和稍后唤醒后),而且不是您想在忙事件管理器处理的每个事件之间执行的操作。

注意,当调用多个事件处理程序时,一个事件处理程序返回hibernate请求整个事件经理进入休眠状态。

除非另有说明,否则如果指定的事件管理器不存在或指定了错误的参数,则此模块中的所有函数都会失败。

数据类型

handler() = atom() | {atom(), term()}

handler_args() = term()

add_handler_ret() = ok | term() | {'EXIT', term()}

del_handler_ret() = ok | term() | {'EXIT', term()}

输出

add_handler(EventMgrRef, Handler, Args) -> Result

类型

向事件管理器添加新的事件处理程序EventMgrRef。事件管理器调用Module:init/1以启动事件处理程序及其内部状态。

EventMgrRef可以是下列任何一种:

  • PID
  • Name,如果事件管理器是本地注册的。
  • {Name,Node},如果事件管理器是在另一个节点本地注册的。
  • {global,GlobalName},如果事件管理器是全局注册的。
  • {via,Module,ViaName},如果事件管理器是通过另一个流程注册表注册的。

Handler是回调模块Module或元组的名称{Module,Id},其中Id是任何术语。该{Module,Id}表示使得当许多事件处理程序使用相同的回调模块可以识别特定的事件处理程序。

Args作为参数传递给Module:init/1...

如果Module:init/1返回表示成功完成的正确值,则事件管理器将添加事件处理函数,并返回此函数ok。如果Module:init/1失败Reason或返回{error,Reason},事件处理程序将被忽略,并且此函数分别返回{'EXIT',Reason}{error,Reason}

add_sup_handler(EventMgrRef, Handler, Args) -> Result

类型

按照相同的方式添加新的事件处理程序add_handler/3,但也监视事件处理程序和调用过程之间的连接。

  • 如果稍后调用进程终止Reason,则事件管理器通过Module:terminate/2{stop,Reason}参数调用来删除事件处理程序。
  • 如果事件处理程序稍后被删除,则事件管理器将发送一条消息。{gen_event_EXIT,Handler,Reason}呼叫进程。Reason为下列之一:
-  `normal`, if the event handler has been removed because of a call to `delete_handler/3`, or `remove_handler` has been returned by a callback function (see below).

-  `shutdown`, if the event handler has been removed because the event manager is terminating.
-  `{swapped,NewHandler,Pid}`, if the process `Pid` has replaced the event handler with another event handler `NewHandler` using a call to [`swap_handler/3`](about:blank#swap_handler-3) or [`swap_sup_handler/3`](about:blank#swap_sup_handler-3).

-  A term, if the event handler is removed because of an error. Which term depends on the error.

有关参数和返回值的说明,请参见add_handler/3...

call(EventMgrRef, Handler, Request) -> Resultcall(EventMgrRef, Handler, Request, Timeout) -> Result

类型

对事件处理程序进行同步调用。Handler安装在事件管理器中EventMgrRef通过发送请求并等待回复到达或超时。事件管理器调用Module:handle_call/2来处理请求。

有关说明EventMgrRefHandleradd_handler/3

Request作为参数之一传递给Module:handle_call/2...

Timeout是一个大于零的整数,用于指定等待答复的毫秒数或原子infinity无限期等待的时间。默认为5000.如果在指定的时间内没有收到回复,则函数调用失败。

返回值Reply是在返回值中定义的Module:handle_call/2。如果未安装指定的事件处理程序,则函数返回{error,bad_module}。如果回调函数失败并Reason返回意外值Term,则此函数分别返回{error,{'EXIT',Reason}}{error,Term}

delete_handler(EventMgrRef, Handler, Args) -> Result

类型

从事件管理器中删除事件处理程序。EventMgrRef事件管理器调用Module:terminate/2若要终止事件处理程序,请执行以下操作。

有关说明EventMgrRefHandleradd_handler/3

Args作为参数之一传递给Module:terminate/2...

返回值是返回值Module:terminate/2。如果未安装指定的事件处理程序,则函数返回{error,module_not_found}。如果回调函数失败Reason,函数返回{'EXIT',Reason}

notify(EventMgrRef, Event) -> oksync_notify(EventMgrRef, Event) -> ok

类型

向事件管理器发送事件通知EventMgrRef。事件管理器要求Module:handle_event/2每个安装的事件处理程序来处理事件。

notify / 2是异步的,并在发送事件通知后立即返回。 sync_notify / 2是同步的,因为在事件被所有事件处理程序处理后,它返回ok。

有关说明EventMgrRef,请参阅add_handler/3

Event作为参数之一传递给Module:handle_event/2...

notify/1即使指定的事件管理器不存在,也不会失败,除非它被指定为Name

start() -> Resultstart(EventMgrName | Options) -> Resultstart(EventMgrName, Options) -> Result

类型

创建一个独立的事件管理器进程,也就是说,事件管理器不是监督树的一部分,因此没有监督者。

有关参数和返回值的说明,请参见start_link/0,1...

start_link() -> Resultstart_link(EventMgrName | Options) -> Resultstart_link(EventMgrName, Options) -> Result

类型

创建事件管理器进程作为监视树的一部分。该职能由主管直接或间接地调用。例如,它确保事件管理器链接到主管。

  • 如果EventMgrName={local,Name},事件管理器在本地注册为Name使用register/2
  • 如果EventMgrName = {global,GlobalName},则使用global:register_name / 2将事件管理器全局注册为GlobalName。 如果没有提供名称,则事件管理器未注册。
  • 如果EventMgrName = {via,Module,ViaName},则事件管理器向Module注册的注册表注册。 Module回调函数是导出函数register_name / 2,unregister_name / 1,whereis_name / 1和send / 2,这些函数在全局中表现为相应的函数。 因此,{via,global,GlobalName}是一个有效的参考。
  • 如果{hibernate_after,HibernateAfterTimeout}存在选项,则gen_event进程等待任何消息HibernateAfterTimeout几毫秒,如果没有收到消息,进程将自动进入休眠状态(通过调用proc_lib:hibernate/3)。

如果事件管理器成功创建,则函数返回{ok,Pid},其中Pid是事件管理器的pid。 如果已经存在指定EventMgrName的进程,则函数返回{error,{already_started,Pid}},其中Pid是该进程的PID。

stop(EventMgrRef) -> okstop(EventMgrRef, Reason, Timeout) -> ok

类型

订单事件管理EventMgrRef器用指定退出Reason并等待它终止。在终止之前,gen_event调用Module:terminate(stop,...)每个已安装的事件处理程序。

如果事件管理器以期望的原因终止,则该函数返回OK。 除正常,关机或{shutdown,Term}之外的任何其他原因都会导致使用error_logger:format / 2发出错误报告。 默认原因是正常的。

Timeout是一个大于零的整数,指定等待事件管理器终止多少毫秒,或者infinity无限期等待原子。默认为infinity。如果事件管理器在指定时间内没有终止,timeout则会引发异常。

如果进程不存在,则引发异常noproc

有关说明EventMgrRef,请参阅add_handler/3

swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result

类型

在事件管理器中用新的事件处理程序替换旧的事件处理程序EventMgrRef

有关参数的描述,请参见add_handler/3...

首先Handler1删除旧的事件处理程序。事件管理器调用Module1:terminate(Args1, ...),这里Module1是回调模块Handler1,并收集返回值。

然后Handler2通过调用来添加和启动新的事件处理程序Module2:init({Args2,Term}),其中Module2回调模块的Handler2Term是返回值Module1:terminate/2。这可以将信息从Handler1Handler2

即使没有安装指定的旧事件处理程序,也会添加新的处理程序。Term=error,或者如果Module1:terminate/2失败Reason,在这种情况下Term={'EXIT',Reason}删除旧的处理程序,即使Module2:init/1失败了。

如果在Handler1和一个过程Pid,之间有一个有监督的联系。Handler2Pid相反。

如果Module2:init / 1返回正确的值,则此函数返回ok。 如果Module2:init / 1因Reason失败或返回意外值Term,则此函数分别返回{error,{'EXIT',Reason}}或{error,Term}。

swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result

类型

在事件管理器EventMgrRef中以与之相同的方式替换事件处理程序swap_handler/3,但也监视Handler2与调用过程之间的连接。

有关参数和返回值的说明,请参见swap_handler/3...

which_handlers(EventMgrRef) -> [Handler]

类型

返回事件管理器中安装的所有事件处理程序的列表EventMgrRef

有关说明EventMgrRefHandleradd_handler/3

回调函数

下面的函数将从gen_event回调模块。

输出

Module:code_change(OldVsn, State, Extra) -> {ok, NewState}

类型

这个回调是可选的,所以回调模块不需要导出它。如果Change={advanced,Extra}在未实现的情况下执行.appup文件中指定的版本升级/降级,code_change/3则事件处理程序将因undef错误原因而崩溃。

此函数针对安装的事件处理程序调用,该处理程序在发行版升级/降级期间更新其内部状态,即在文件中指定指令{update,Module,Change,...}where 时。有关更多信息,请参阅Change={advanced,Extra}.appupOTP Design Principles

对于升级,OldVsn是Vsn,对于降级,OldVsn是{down,Vsn}。 Vsn由回调模块Module的旧版本的vsn属性定义。 如果未定义此类属性,则版本是Beam文件的校验和。

State事件处理程序的内部状态。

Extra{advanced,Extra}更新指令的一部分。

函数是返回更新的内部状态。

Module:format_status(Opt, [PDict, State]) -> Status

类型

此回调是可选的,因此事件处理程序模块不需要导出它。如果处理程序不导出此函数,则gen_event模块直接将处理程序状态用于以下目的。

此函数由gen_event在下列情况下处理:

  • sys之一:get_status / 1,2被调用以获得gen_event状态。 对于这种情况,Opt被设置为正常原子。
  • 事件处理程序异常终止,并且gen_event记录错误。Opt被设置为原子terminate为了这个案子。

此函数对于更改这些情况下事件处理程序状态的形式和外观很有用。事件处理程序回调模块希望更改sys:get_status/1,2返回值以及其状态在终止错误日志中的显示方式,导出一个实例format_status/2返回描述事件处理程序当前状态的术语。

PDict是过程字典的当前值gen_event

State事件处理程序的内部状态。

该函数返回Status一个改变事件处理程序当前状态细节的术语。任何术语都是允许的Status。该gen_event模块使用Status如下:

  • 何时sys:get_status/1,2被调用,gen_event确保其返回值包含Status事件处理程序的状态项。
  • 当事件处理程序异常终止时,gen_event将记录事件处理程序Status的状态项。

此功能的一个用途是返回紧凑的替代状态表示,以避免在日志文件中打印大型状态项。

Module:handle_call(Request, State) -> Result

类型

每当事件管理器收到使用call/3,4,则为指定的事件处理程序调用此函数以处理请求。

RequestRequest争论call/3,4...

State事件处理程序的内部状态。

返回值与Module:handle_event / 2的返回值相同,除了它们还包含一个术语Reply,它是作为调用/ 3,4的返回值对客户端的答复。

Module:handle_event(Event, State) -> Result

类型

每当事件管理器接收到使用notify/2or 发送的事件时sync_notify/2,就会为每个安装的事件处理程序调用此函数来处理事件。

Event是notify / 2 / sync_notify / 2的Event参数。

State事件处理程序的内部状态。

  • 如果{ok,NewState}或{ok,NewState,hibernate}被返回,则事件处理程序保持在事件管理器中,并且可能更新内部状态NewState。
  • 如果{ok,NewState,hibernate}返回,事件管理器也会通过调用进入休眠状态proc_lib:hibernate/3,等待下一个事件发生。只要其中一个事件处理程序返回{ok,NewState,hibernate}整个事件管理器进程即可休眠。
  • 如果{swap_handler,Args1,NewState,Handler2,Args2}返回,则事件处理程序Handler2由第一次调用替换Module:terminate(Args1,NewState),然后Module2:init({Args2,Term})Term返回值为Module:terminate/2。有关更多信息,请参阅swap_handler/3
  • 如果remove_handler返回时,将通过以下方式删除事件处理程序:Module:terminate(remove_handler,State)...

Module:handle_info(Info, State) -> Result

类型

这个回调是可选的,所以回调模块不需要导出它。该gen_event模块提供了该功能的默认实现,该实现记录了意外Info消息,并将其丢弃并返回{noreply, State}

当事件管理器收到除事件或同步请求(或系统消息)之外的任何其他消息时,将为每个已安装的事件处理程序调用此函数。

Info是接收到的消息。

有关State可能的返回值的说明,请参阅Module:handle_event/2

Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}

类型

每当向事件管理器添加新的事件处理程序时,都会调用此函数来初始化事件处理程序。

如果事件处理程序是因为调用add_handler/3or 而添加的add_sup_handler/3InitArgsArgs这些函数的参数。

如果事件处理程序由于调用swap_handler / 3或swap_sup_handler / 3或由于其他回调函数之一的交换返回元组而替换另一个事件处理程序,则InitArgs是一个元组{Args,Term},其中Args是 参数在函数调用/返回元组中提供,Term是终止旧事件处理程序的结果,请参阅swap_handler / 3。

如果成功,则函数返回{ok,State}{ok,State,hibernate},其中State是事件处理程序的初始内部状态。

如果{ok,State,hibernate}返回,则事件管理器进入休眠状态(通过调用proc_lib:hibernate/3),等待下一个事件发生。

Module:terminate(Arg, State) -> term()

类型

这个回调是可选的,所以回调模块不需要导出它。该gen_event模块提供了一个没有清理的默认实现。

每当从事件管理器中删除事件处理程序时,都会调用此函数。它将是与之相反的Module:init/1做任何必要的清理。

如果事件处理程序,因为一个电话而被删除到delete_handler/3swap_handler/3或者swap_sup_handler/3ArgArgs这个函数调用的参数。

Arg={stop,Reason}如果事件处理程序具有监督连接到已经以理由终止的进程Reason

Arg=stop 如果事件处理程序因事件管理器正在终止而被删除。

如果事件管理器是监督树的一部分,并且由其主管命令终止,则事件管理器将终止。即使是监视树的一部分,如果接收到'EXIT'它的父消息。

Arg=remove_handler如果由于另一个回调函数返回而删除了事件处理程序remove_handler{remove_handler,Reply}...

Arg={error,Term}如果由于回调函数返回意外值而删除事件处理程序Term,或Arg={error,{'EXIT',Reason}}如果回调函数失败。

State事件处理程序的内部状态。

函数可以返回任何术语。如果事件处理程序由于调用gen_event:delete_handler/3,则该函数的返回值将变为此函数的返回值。如果由于交换而将事件处理程序替换为另一个事件处理程序,则返回值将传递给init新事件处理程序的函数。否则,将忽略返回值。

另见

supervisor(3)sys(3)

stdlib/gen_event相关

Erlang 20

Erlang 是一种通用的面向并发的编程语言,可应付大规模开发活动的程序设计语言和运行环境。

主页 https://www.erlang.org/
源码 https://github.com/erlang/otp
版本 20
发布版本 20.1