OTP行为模式浅析之(gen_server、application、supervisor)

时间:2024-03-29 20:39:24

行为模式是面向进程编程中各种常见模式的一种形式化表述。OTP行为模式将Erlang进程执行的代码分为库模块和实现模块。在开发标准、并发、容错的OTP代码时,大部分的复杂性都可以靠行为模式来消解。


行为模式的三个内容

·行为模式接口:是一组特定的函数和相关的调用规范(这些函数也被称为回调函数)。

·行为模式实现:是一个导出了接口(对接库模块与实现模块的接口)所需的全部函数的回调模块(即是对行为模式接口  的实现)。实现模块应包含-behaviour(...),协助编译器检查模块是否完整导出了接口所需的所有函  数。

·行为模式容器:容器是一个进程,它执行的是某个库模块中的代码,并且会调用与行为模式实现相对应的回调模块来处  理应用相关的逻辑。(库代码可以处理同步消息、进程初始化,以及进程清理与终止等事务,还提供了  一系列挂接点,以便将模块融入代码变更框架和监督树等更大的OTP模式和结构。)

总结:行为模式接口就是让行为模式实现(你编写的代码)发挥出行为模式容器能力的契约。


gen_server (通用服务器)行为模式

·行为模式的接口函数:init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3。

·你在API中用到的每个gen_server库函数都有一个gen_server行为模式接口指定的回调函数与之对应。当你在API中调用库函数,库函数会调用回调函数,部分调用关系如下图所示。

OTP行为模式浅析之(gen_server、application、supervisor)

注意:回调函数的返回值被用于与gen_server容器进程通信。


application (应用)行为模式

·行为模式的接口函数:start/2,stop/1。

·每个主动应用都配有一个application行为模式的实现模块,该模块用于实现系统启动逻辑,至少要负责根监督者的启动。

·创建OTP应用要做3件事:1、建立标准目录结构;2、添加用于存放应用元数据的.app文件;3、创建一个application行为模式实现模块,负责启动应用。

·.app文件中的mod参数,用于告知系统如何启动应用,其值是一个元组,包含一个模块名和一些可选的启动参数,该模块必须实现application行为模式。


supervisor (监督者)行为模式

·行为模式的接口函数:init/1。

·示例代码:

OTP行为模式浅析之(gen_server、application、supervisor)

OTP行为模式浅析之(gen_server、application、supervisor)

·API函数start_link()负责启动监督者。库函数supervisor:start_link/3的第一个参数是二元组{local, ?SERVER},用于让OTP库在本地节点上以模块名为注册名自动注册监督进程。第三个参数是传给回调函数init/1的启动参数。

·子进程的启动策略①管理策略②以及重启策略都是经由init/1函数的返回值告知给OTP监督者库的。

·重启策略({RestartStrategy, Max, Period},在Period秒内最多重启Max次子进程,启动失败则监督者终止):

  • one_for_one -如果一个子进程终止并将要重启,只有这个子进程受影响。这是默认的重启策略。
  • one_for_all -如果一个子进程终止并将要重启,其他所有的子进程都会被终止,然后所有的子进程都会被重启。
  • rest_for_one  -如果一个子进程终止并将要重启,在启动顺序位于终止的子进程之后的子进程都会终止,然后终止的子进程和所有位于它之后的子进程都会被重启。
  • simple_one_for_one -简化的one_for_one 监督者,其所有子进程都会动态添加相同进程类型的实例,也就是说,执行相同代码。                                                                                                                                

    对于 simple_one_for_one 监督者,函数 delete_child/2 和 restart_child/2 是非法的,并会返回{error,simple_one_for_one} 。

    对于通过指定子进程pid作为第二参数的 simple_one_for_one 监督者的子进程,函数 terminate_child/2 可以使用。如果相反,子进程规范标识符被使用了, terminate_child/2 会返回{error,simple_one_for_one} 。

    作为一个 simple_one_for_one 监督者可以有很多子进程, 它会异步地关闭所有子进程。这意味着子进程会平行地执行他们的清除,因此它们的停止顺序是没有定义的。

参考书籍:《Erlang/OTP并发编程实战》