论坛首页 综合技术论坛

erlang:send_after和erlang:start_timer的使用解释

浏览 7895 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-04-06  
前段时间arksea 同学提出这个问题, 因为文档里面写的很不明白.

    erlang:send_after(Time, Dest, Msg) -> TimerRef
    Time = int()
    0 <= Time <= 4294967295
    Dest = pid() | RegName
    LocalPid = pid() (of a process, alive or dead, on the local node)
    Msg = term()
    TimerRef = ref()
    Starts a timer which will send the message Msg to Dest after Time milliseconds.

    If Dest is an atom, it is supposed to be the name of a registered process. The process referred to by the name is looked up at the time of delivery. No error is given if the name does not refer to a process.

    If Dest is a pid, the timer will be automatically canceled if the process referred to by the pid is not alive, or when the process exits. This feature was introduced in erts version 5.4.11. Note that timers will not be automatically canceled when Dest is an atom.

    See also erlang:start_timer/3, erlang:cancel_timer/1, and erlang:read_timer/1.

    Failure: badarg if the arguments does not satisfy the requirements specified above.

    erlang:start_timer(Time, Dest, Msg) -> TimerRef
    Time = int()
    0 <= Time <= 4294967295
    Dest = LocalPid | RegName
    LocalPid = pid() (of a process, alive or dead, on the local node)
    RegName = atom()
    Msg = term()
    TimerRef = ref()
    Starts a timer which will send the message {timeout, TimerRef, Msg} to Dest after Time milliseconds.

    If Dest is an atom, it is supposed to be the name of a registered process. The process referred to by the name is looked up at the time of delivery. No error is given if the name does not refer to a process.

    If Dest is a pid, the timer will be automatically canceled if the process referred to by the pid is not alive, or when the process exits. This feature was introduced in erts version 5.4.11. Note that timers will not be automatically canceled when Dest is an atom.

    See also erlang:send_after/3, erlang:cancel_timer/1, and erlang:read_timer/1.

    Failure: badarg if the arguments does not satisfy the requirements specified above.

表面上看这2个API没有什么大的差别,使用上也一样, 那为什么要搞二个呢? 好奇怪!

好, 让我们来好好研究下典型应用.

这2个API都返回 TimerRef. 用户可以用这个TimerRef来取消定时器. 唯一的差别是在超时的时候发送的消息不同: send_after是Msg, start_timer是{timeout, TimerRef, Msg}.
问题就出在取消timer的时候. 如果这个timer还没有超时的时候, 那么取消就没问题. 如果超时了麻烦就来了, 这个消息已经有可能已经被放到目标进程的消息队列里,等待派遣处理了.

这时候send_after里面存放的是Msg, 那用户如何知道Msg是对于那个TimerRef的呢? 读者可能说, 那我可以在消息里面加入TimerRef. 这个主意不错, 但是问题是在send_after调用返回之前, 你是无法得到TimerRef, 当然也就无从构造这个消息, 那就无法处理这个可能的超时信息, 就会破坏逻辑.
所以erts version 5.4.11 引入了, start_timer来解决这个问题. 它是自动的在超时后, 要发送消息前, 在消息里面添加了{timeout, TimerRef, Msg}, 达到识别的目的.

结论: 文档里面一眼带过的东西, 其实是有很多设计方面的考虑, 要认真考虑它的存在的意义.
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics