1.截至目前群里的成员已经对skynet中的timeout提出了更多的要求。目前skynet提供的定时器是倒计时形式,且定时器一旦设置后,便不能撤销(至少目前的实现是这样),然后调用 cb

最近有人提出希望能支持一下撤销定时器的功能,但云风坚持:“框架只应该提供必不可少的特性,能用已有的特性实现的东西都应该删掉”。

2.这里为什么说伪取消定时器呢?

  skynet中当调用 skynet.timeout(time, cb)以后,便进入skynet_timer.c中管理,然后到时以后,将到时消息放到调用服务的消息队列上,等待回调函数处理。

  真正的取消定时器是党调用取消定时器的接口后,停止倒计时同时将本次任务从某个地方彻底删除,好像什么事都没发生一样。

  那么伪取消就是倒计时继续执行,只是当倒计时结束以后回调函数执行时,执行的不是调用定时器时注册的回调,而是更改了的回调,这个回调不会做任何事情,由此来实现伪取消。

3.伪取消定时器的思路

  首先看下skynet.timeout()。

  1. function skynet.timeout(ti, func)
  2. local session = c.intcommand("TIMEOUT",ti)
  3. assert(session)
  4. local co = co_create(func)
  5. assert(session_id_coroutine[session] == nil)
  6. session_id_coroutine[session] = co
  7. return session
  8. end

1) 用"TIMEOUT"命令启动本次倒计时,并返回一个session,然后用回掉函数创建一个协程,创建协程代码如下:

  1. local function co_create(f)
  2. local co = table.remove(coroutine_pool)
  3. if co == nil then
  4. co = coroutine.create(function(...)
  5. f(...)
  6. while true do
  7. f = nil
  8. coroutine_pool[#coroutine_pool+] = co
  9. f = coroutine_yield "EXIT"
  10. f(coroutine_yield())
  11. end
  12. end)
  13. else
  14. coroutine_resume(co, f)
  15. end
  16. return co
  17. end

用于本虚拟机中的协程池,coroutine_pool只会在这个函数使用,即如果池子里为空,则用 f 创建新协程并放到池子里,若有协程重新注册 回调函数为 f。

2)用session_id_coroutine[session] = co来保存session与co的对应关系,当倒计时结束后会根据co来得到session。timeout函数到此就结束了,就这样然后就看可以利用框架来实现倒计时结束后调用回调。看似也没做什么,真正的奥秘在

local session = c.intcommand("TIMEOUT",ti).

手里有源码的可以直接跟进去,看一下到底做了什么.

那么调用回调的地方在哪里呢?在 skynet.draw_dispatch_message(...)中。

  1. function skynet.dispatch_message(...)
  2. local succ, err = pcall(raw_dispatch_message,...)
  3. while true do
  4. local key,co = next(fork_queue)
  5. if co == nil then
  6. break
  7. end
  8. fork_queue[key] = nil
  9. local fork_succ, fork_err = pcall(suspend,co,coroutine_resume(co))
  10. if not fork_succ then
  11. if succ then
  12. succ = false
  13. err = tostring(fork_err)
  14. else
  15. err = tostring(err) .. "\n" .. tostring(fork_err)
  16. end
  17. end
  18. end
  19. assert(succ, tostring(err))
  20. end
  21.  
  22. local function raw_dispatch_message(prototype, msg, sz, session, source)
  23. -- skynet.PTYPE_RESPONSE = 1, read skynet.h
  24. if prototype == then
  25. local co = session_id_coroutine[session]
  26. if co == "BREAK" then
  27. session_id_coroutine[session] = nil
  28. elseif co == nil then
  29. print("prototype, msg, sz, session, source: ", prototype, msg, sz, session, source)
  30. unknown_response(session, source, msg, sz)
  31. else
  32. session_id_coroutine[session] = nil
  33. suspend(co, coroutine_resume(co, true, msg, sz))
  34. end
  35. else
  36. local p = proto[prototype]
  37. if p == nil then
  38. if session ~= then
  39. c.send(source, skynet.PTYPE_ERROR, session, "")
  40. else
  41. unknown_request(session, source, msg, sz, prototype)
  42. end
  43. return
  44. end
  45. local f = p.dispatch
  46. if f then
  47. local ref = watching_service[source]
  48. if ref then
  49. watching_service[source] = ref +
  50. else
  51. watching_service[source] =
  52. end
  53. local co = co_create(f)
  54. session_coroutine_id[co] = session
  55. session_coroutine_address[co] = source
  56. suspend(co, coroutine_resume(co, session,source, p.unpack(msg,sz)))
  57. else
  58. unknown_request(session, source, msg, sz, proto[prototype].name)
  59. end
  60. end
  61. end

倒计时结束后会执行标黄代码的逻辑:

session_id_coroutine[session] = nil

suspend(co, coroutine_resume(co, true, msg, sz))

这时根据 session 得到co,这个co便是回调的协程。

前面讲到,为取消就是将这个co在为到时之前替换成什么都不执行的一个co。而替换的关键:1.几下第一次timeout时desession;2,重新生成一个co。这两个点都可以在skynet.lua中实现,代码如下:

  1. local function remove_timeout_cb(...)
  2. end
  3.  
  4. function skynet.remove_timeout(session)
  5. local co = co_create(remove_timeout_cb)
  6. assert(session_id_coroutine[session] ~= nil)
  7. session_id_coroutine[session] = co
  8. end
  9.  
  10. function skynet.timeout(ti, func)
  11. local session = c.intcommand("TIMEOUT",ti)
  12. assert(session)
  13. local co = co_create(func)
  14. assert(session_id_coroutine[session] == nil)
  15. session_id_coroutine[session] = co
  16. return session
  17. end

可以看到,增加了skynet.remove_timeout和skynet.remove_timeout_cb(),同时 skynet.timeout()中返回了获得的session。代码很简单,就是照着前面的思路实现的。

4.测试代码:

  1. local session = skynet.timeout(, function() print("test timeout 10") end)
  2. skynet.remove_timeout(session)
  3. skynet.timeout(, function() print("test timeout 15") end)

5.测试过程:

  1)修改skynet.lua,增加skynet.remove_timeout和skynet.remove_timeout_cb(),同时使skynet.timeout返回产生的session。

   2)修改配置文件config,start = "testtimer" 将start的脚本改为test下的testtimmer,测试将在那里进行。

   3)在testtimer.lua中的skynet.start中使用上边三局测试代码,或者自己编写,便可得到结果。

到此,一个skyent的伪取消定时器实现了。当然可以通过向类似c.Initcommand("TIMEOUT", t1)这中形式,自己实现"REMOVE_TIMEOUT"命令,只是这样更改的地方较多,但是可以实现彻底取消。

今天实现了临时的取消,正着手创建新命令来彻底取消。特此记录,欢迎指正与指教。

  

skynet之伪取消定时器的更多相关文章

  1. javascript定时器,取消定时器,及js定时器优化方法

    通常用的方法: 启动定时器: window.setInterval(Method,Time) Method是定时调用的js方法 Time是间隔时间,单位是毫秒 取消定时器: clearInterval ...

  2. JavaScript 定时器 取消定时器

    感谢:链接(视频讲解很清晰) 定时器:作用主要是一定时间间隔后,做出相关的变化,例如图片轮播. 目录 两种定时器的使用 两种定时器区别 取消定时器的方法 两种定时器的使用: 方法一:setTimeou ...

  3. skynet记录6:定时器

    稍后填坑 kernel中,每一次时钟中断会trap到kernel code,这个时间间隔称之为jiffies,每秒钟发生的次数为HZ 如果是4核,分配到每个核就是HZ/4 cat /boot/conf ...

  4. 深入理解定时器系列——被誉为神器的requestAnimationFrame

    与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好处呢?为什么requestAnimationFrame被称为神器呢?本文将详 ...

  5. 深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame

    × 目录 [1]引入 [2]特点 [3]使用[4]兼容[5]应用 前面的话 与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好 ...

  6. GCD定时器

    // // ViewController.m // GCD 定时器 // // #import "ViewController.h" NSInteger count = ; @in ...

  7. iOS--NSTimer设置定时器的两种方法

    //方法一: //创建定时器 NSTimer *timer=[NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(next ...

  8. IOS GCD定时器

    提到定时器,NStimer肯定是我们最为熟悉的. 但是NStimer有着很大的缺点,并不准确. 通俗点说,就是它该做他的事了,但是由于其他事件的影响,Nstimer会放弃他应该做的. 而GCD定时器, ...

  9. IOS中定时器NSTimer的开启与关闭

    调用一次计时器方法: myTimer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(scro ...

随机推荐

  1. [LintCode] 最后一个单词的长度

    class Solution { public: /** * @param s A string * @return the length of last word */ int lengthOfLa ...

  2. 表单验证 靠name获取

    表单 靠name获取 <form class="add-form" name="form" action="#" method=&qu ...

  3. “绝对”妹纸~position

    CSS:布局之fixed,relative,absolute 记住abs是跟随 relative的,没有看到position:relative;之前他会一直向上查找. 直到执着的找到relative! ...

  4. 第5章 IDA Pro

    5.1 加载一个可执行文件 默认情况下IDA Pro的反汇编代码中不包含PE头或资源节,可以手动指定加载. 5.2 IDA Pro接口 5.2.1 反汇编窗口模式 二进制模式/图形模式: 图形模式:红 ...

  5. Oracle Database Documentation

    Oracle数据库的发展简史 ORDBMS对象-关系数据库管理系统 Oracle Schema Objects Oracle Schema Objects——Tables——Overview of T ...

  6. The OpenCV Coding Style Guide

    https://github.com/opencv/opencv/wiki/Coding_Style_Guide

  7. 容灾 RPO RTO

    w https://en.wikipedia.org/wiki/Recovery_point_objective A recovery point objective, or “RPO”, is de ...

  8. django--之登录表单提交

    前端代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  9. python学习之路-第八天-文件IO、储存器模块

    文件IO.储存器模块 文件IO 代码示例: # -*- coding:utf-8 -*- #! /usr/bin/python # filename:using_file.py poem = '''\ ...

  10. Python基础总结(字符串常用,数字类型转换,基本运算符与流程控制)

    一.字符串常用操作 #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格) name='*egon**' print(name.strip('*'))#移除 name 变量对应 ...