[Erlang09]Erlang gen_server实现定时器(interval)的几种方法及各自的优缺点?
方法1:
%%gen_server:部分call_back function.
-define(TIME,1000). init([]) –>
erlang:send_after(?TIME,self(),loop_interval_event),
{ok, #state{}}. handle_info(loop_interval_event, State) –>
NewState = do_loop_interval_event(State),
erlang:send_after(?TIME,self(),loop_interval_event),
{noreply, NewState}.
优点:可以加任意多个定时器,且可以保证do_loop_interval_event/1处理完后才触发第二个定时器【想像一个如果处理event 200ms,处理间隔是150ms,那么这个进程还是可以不阻塞消息队列的】.这种方法也是推荐使用的。
缺点: 如果项目有很多的进程都有定时器,大家都调用系统函数来判定时间,性能消耗会增大【这个=下讲原因】。
方法2:
%%在gen_server:call back function 返回值加入一个时间
init([]) –>
{ok, #state{},?TIME}.
handle_info(timeout,State = #state{count = Count}) –>
io:format("timeout:~w~n",[Count]),
{noreply,State#state{count = Count+1},?TIME}.
原理:利用gen_server: init返回值如果是{ok,State,TimeTemp}时会在TimeTemp后发出一个timeout信息,给handle_info处理,然后handle_info处理后再设置返回值的time,又会循环触发这个timeout事件,完成定循环功能
缺点:只能使用一个定时事件哦,就是timeout,且会被其它的call back function :handle_call,handle_cast,影响,因为如果他们的返回值也加入这个TIME,也会触发同一个timeout事件….
其实gen_server可以设置这个timeout事件,主要目的还是为了怕回调函数处理消息太慢,如果太慢了,就执行相同的timeout做相关处理。
方法3:
%%使用timer:send_interval/3设置事件间隔
init([]) –>
timer:send_interval(?TIME,self(),loop_interval_event),
{ok, #state}.
handle_info(loop_interval_event, State) ->
NewState = do_loop_inverval_event(State),
{noreply, NewState};
send_interval/3
Evaluates Pid ! Message repeatedly after Time amount of time has elapsed. (Pid can also be an atom of a registered name.) Returns {ok, TRef} or {error, Reason}.
就是每隔TIME时间就给Pid发一个Msg,(相当于每TIME Pid ! Msg).
缺点:timer自已本身就是一个gen_server进程,如果在SMP下大量进程要使用这个进程来频繁调度也是很吃力的.
优点:当然是简单且可以设置多个。
以上只是小菜,下面来看看erlang 神秘的time及为什么大部分人都视timer模块为毒药?
erlang使用time有4种方式:
| 语法层:receive after | opcode实现,timeout立即把进程加入到调度队列 | 使用非常多,也是最高效的 |
| BIF: erlang: send_after/3 erlang: send_timer/3 |
timout 立即给Dest Pid发送Msg |
使用较多 |
| gen_server: timer模块 |
使用gen_server统一管理用一个ets的管理实现 | 统一管理erts 定时器 |
| driver: int driver_set_timer(ErlDrvPort port, unsigned long time); |
tcp/udp进程需要超时处理,所以有大量的连接的时候这种timer的数量非常大,定时器超时后把port_task加到调度队列 | inet_driver大量使用这个api. 这个没用到,不是很懂… |
这上面只有timer模块是用erlang写的,那么,我们来好好研究下这个简单而有趣的timer模块吧。
timer是一个典型的gen_server模块,非常简单明了,只有500行左右,也可以做为学习写好gen_server的一个模板:你可以点击这里看源码

它随kernel application起动,被kernel_safe_sup监控,注册名为timer_server。是一个标准的gen_server模块,我们现在来看看它有趣的地方:
它的实现主要是依赖于gen_server call back里面如果:init/1,hande_call/3 ,handle_info/2,handle_cast/2 返回值加入TimeOut参数,那么经过TimeOut时间后,会触发一个timeout事件给handle_info处理。

问题:
1. 为什么大部分人视timer为毒药呢?他的局限性是什么?
timer设计的目的就是:统一管理多少时长后发生的事件,是一个manager进程,同时也是一个单进程,这样的短板:如果大量的事件都在这里面时,就会使这个进程负荷太大,出现各种不稳定bug.这就是大部分人不也使用它的原因;
2. 什么时候可以使用它呢?
首先,要明白为什么为把这些事件用timer来统一管理,因为如果大量进程自己内部调用erlang: send_after/3,即当用erlang: send_after/3导致的开销大于使用timer的开销时,自然,我们就会想自己设计一个统一的管理进程来取代每个work进程自己单独用erlang: send_after/3发信息处理:即manger进程 每隔一段时间就给work进程发消息来代替erlang: send_after/3. 自己造这个轮子也可以,不过在这时使用timer模块来处理再好不过啦!!!!
Tip:你可以使用timer:get_status()来查看这个进程的负载情况
关于timer的误解:
1. 所有timer模块都是单进程的,使用一定要慎重考虑再考虑!
The functions in the timer module that do not manage timers (such as timer:tc/3 or timer:sleep/1), do not call the timer-server process and are therefore harmless.
有一些timer内不管理时间定时器的函数 例如:
sleep/1,
tc/1, tc/2, tc/3,
now_diff/2,
seconds/1, minutes/1, hours/1, hms/3
不去调用定时器server进程的函数都是无害的。【也就是说:有些timer里面的函数是不依赖于这个server的,可以随意用】
2. Warning:
A timer can always be removed by calling cancel/1.
An interval timer, i.e. a timer created by evaluating any of the functions apply_interval/4, send_interval/3, and send_interval/2, is linked to the process towards which the timer performs its task.
A one-shot timer, i.e. a timer created by evaluating any of the functions apply_after/4, send_after/3, send_after/2, exit_after/3, exit_after/2, kill_after/2, and kill_after/1 is not linked to any process. Hence, such a timer is removed only when it reaches its timeout, or if it is explicitly removed by a call to cancel/1.
[Erlang09]Erlang gen_server实现定时器(interval)的几种方法及各自的优缺点?的更多相关文章
- [转]Qt中定时器使用的两种方法
Qt中定时器的使用有两种方法,一种是使用QObject类提供的定时器,还有一种就是使用QTimer类. 其精确度一般依赖于操作系统和硬件,但一般支持20ms.下面将分别介绍两种方法来使用定时器. 方法 ...
- 【erlang】执行linux命令的两种方法
os.cmd(Cmd) os模块提供了cmd函数可以执行linux系统shell命令(也可以执行windows命令).返回一个Cmd命令的标准输出字符串结果.例如在linux系统中执行os:cmd(& ...
- Linux下实现定时器Timer的几种方法
http://blog.csdn.net/lxmky/article/details/7669296 第六章 IO复用:select和poll函数 http://www.cnblogs.com/4ti ...
- 关于C#中Timer定时器的重入问题解决方法(也适用于多线程)
项目中用到了定时器随着服务启动作定时任务,按指定的准点时间定时执行相关操作,但是在指定准点时间内我只想让它执行一次,要避免重入问题的发生. 首先简单介绍一下timer,这里所说的timer是指的Sys ...
- java:JavaScript2:(setTimeout定时器,history.go()前进/后退,navigator.userAgent判断浏览器,location.href,五种方法获取标签属性,setAttribute,innerHTML,三种方法获取form表单信息,JS表单验证,DOM对象,form表单操作)
1.open,setTimeout,setInterval,clearInterval,clearTimeout <!DOCTYPE> <html> <head> ...
- Spring4定时器 cronTrigger和simpleTrigger实现方法
spring4定时器 cronTrigger和simpleTrigger实现方法 Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz 允许 ...
- Android 定时器实现的几种方式和removeCallbacks失效问题详解
实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + Runnable的方式 Handler handler = new Handler(); Runnable runna ...
- 【转】Android 定时器实现的几种方式和removeCallbacks失效问题详解--不错
原文网址:http://blog.csdn.net/xiaanming/article/details/9011193 实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + ...
- erlang下lists模块sort(排序)方法源码解析(二)
上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...
随机推荐
- css伪类(Pseudo-classes)
简介:伪类(Pseudo classes)是选择符的螺栓,用来指定一个或者与其相关的选择符的状态.它们的形式是selector:pseudo class { property: value; },简单 ...
- 如何查找EI 及SCI 索引
1.EI https://www.engineeringvillage.com/search/quick.url 搜题目,然后点击搜索,然后点击细节(detailed) Accession numbe ...
- OpenLayers 3 之 地图视图(View)
OpenLayers 3 之 地图视图(View) 初始化一幅地图,必备的三要素之一视图(view),这个对象主要是控制地图与人的交互,如进行缩放,调节分辨率.地图的旋转等控制.也就是说每个 map对 ...
- C#做的在线升级小程序
转自原文C#做的在线升级小程序 日前收到一个小任务,要做一个通用的在线升级程序.更新的内容包括一些dll或exe或.配置文件.升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的 ...
- Shiro配置cookie以及共享Session和Session失效问题
首先我们看Shiro的会话管理器的配置 <!-- shiro会话管理 --> <!-- 即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中:会话可以是普通 JavaSE ...
- linux命令 环境设置 顺序
转 http://blog.csdn.net/dingxy/article/details/4016383 在登录Linux时要执行文件的过程如下: 在刚登录Linux时,首先启动 /etc/prof ...
- Asp.Net 自定义 httpmodel 中间件 管道
https://msdn.microsoft.com/en-us/library/aa719858(v=vs.71).aspx http://www.cnblogs.com/jimmyzhang/ar ...
- StringUtils.hasText()
StringUtils.hasText(字符串) 如果字符串里面的值为null, "", " ",那么返回值为false:否则为true
- springboot 中使用thymeleaf
Spring Boot支持FreeMarker.Groovy.Thymeleaf和Mustache四种模板解析引擎,官方推荐使用Thymeleaf. spring-boot-starter-thyme ...
- Lucene的查询及高级内容
Lucene查询 基本查询: @Test public void baseQuery() throws Exception { //1. 创建查询的核心对象 FSDirectory d = FSDir ...