方法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)的几种方法及各自的优缺点?的更多相关文章

  1. [转]Qt中定时器使用的两种方法

    Qt中定时器的使用有两种方法,一种是使用QObject类提供的定时器,还有一种就是使用QTimer类. 其精确度一般依赖于操作系统和硬件,但一般支持20ms.下面将分别介绍两种方法来使用定时器. 方法 ...

  2. 【erlang】执行linux命令的两种方法

    os.cmd(Cmd) os模块提供了cmd函数可以执行linux系统shell命令(也可以执行windows命令).返回一个Cmd命令的标准输出字符串结果.例如在linux系统中执行os:cmd(& ...

  3. Linux下实现定时器Timer的几种方法

    http://blog.csdn.net/lxmky/article/details/7669296 第六章 IO复用:select和poll函数 http://www.cnblogs.com/4ti ...

  4. 关于C#中Timer定时器的重入问题解决方法(也适用于多线程)

    项目中用到了定时器随着服务启动作定时任务,按指定的准点时间定时执行相关操作,但是在指定准点时间内我只想让它执行一次,要避免重入问题的发生. 首先简单介绍一下timer,这里所说的timer是指的Sys ...

  5. java:JavaScript2:(setTimeout定时器,history.go()前进/后退,navigator.userAgent判断浏览器,location.href,五种方法获取标签属性,setAttribute,innerHTML,三种方法获取form表单信息,JS表单验证,DOM对象,form表单操作)

    1.open,setTimeout,setInterval,clearInterval,clearTimeout <!DOCTYPE> <html> <head> ...

  6. Spring4定时器 cronTrigger和simpleTrigger实现方法

    spring4定时器 cronTrigger和simpleTrigger实现方法 Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz 允许 ...

  7. Android 定时器实现的几种方式和removeCallbacks失效问题详解

    实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + Runnable的方式 Handler handler = new Handler(); Runnable runna ...

  8. 【转】Android 定时器实现的几种方式和removeCallbacks失效问题详解--不错

    原文网址:http://blog.csdn.net/xiaanming/article/details/9011193 实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + ...

  9. erlang下lists模块sort(排序)方法源码解析(二)

    上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...

随机推荐

  1. C#:Json数据反序列化为Dictionary并根据关键字获取指定的值

    转自曾是土木人原文 C#:Json数据反序列化为Dictionary并根据关键字获取指定的值 Json数据: { "dataSet": { "header": ...

  2. UNITY 画布的粗浅理解

    画布:当画布是screen-space overlay时,这个好理解,画布可以控制如分辨率,层次等.但当画布是 world-space时,这个严格来说就不算是一个画布了,屏幕空间或相机空间的画布是先绘 ...

  3. Cross-Browser, Event-based, Element Resize Detection(转)

    DOM Elements! Y U No Resize Event? During your coding adventures, you may have run into occasions wh ...

  4. Mysql安装配置,修改初试密码。

    绿色版本,解压缩 D:\Software\mysql-advanced-5.6.18-winx64 my-default.ini 改名my.ini my.ini内容如下 # For advice on ...

  5. 读取properties文件并获取属性值

    1.Properties与ResourceBundle 两个类都可以读取属性文件中以key/value形式存储的键值对,ResourceBundle读取属性文件时操作相对简单. 2.Propertie ...

  6. fsync性能问题

    最近在测试种发现程序里调用fsync刷文件到磁盘时,开销只有几百微秒,于是对fsync相关机制进行了一番调查. 磁盘(或RAID卡)自身通常会有硬件缓存机制,对于写操作,有write back和wri ...

  7. 《Android Studio实用指南》7.1 AndroidStudio代码检查工具概述

    本文节选自<Android Studio实用指南> 作者: 毕小朋 目前本书已上传到百度阅读, 在百度中搜索[Anroid Studio实用指南]便可以找到本书. Android Stud ...

  8. java-tip-关于StringBuilder的使用

    当我们需要拼接字符串时,通常会使用StringBuilder,这里简单分析下StringBuilder的内部结构. StringBuilder内部是一个char数组,当调用append方法连接字符串时 ...

  9. SpringBoot中使用AOP实现计算Service执行时间

    1.增加POM.XML的依赖架包 <!-- 引入 spring aop 依赖 --><dependency> <groupId>org.springframewor ...

  10. Webdings和Wingdings字符码对应表

    刚才研究动网论坛代码,发现一个页面提示标记 i 感觉很神奇,看了半天才明白原来是一种叫“Webdings”的字体,其实很简单,只需要<font face='webdings' size=&quo ...