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

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

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

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

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

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

3.伪取消定时器的思路

  首先看下skynet.timeout()。

function skynet.timeout(ti, func)
local session = c.intcommand("TIMEOUT",ti)
assert(session)
local co = co_create(func)
assert(session_id_coroutine[session] == nil)
session_id_coroutine[session] = co
return session
end

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

local function co_create(f)
local co = table.remove(coroutine_pool)
if co == nil then
co = coroutine.create(function(...)
f(...)
while true do
f = nil
coroutine_pool[#coroutine_pool+] = co
f = coroutine_yield "EXIT"
f(coroutine_yield())
end
end)
else
coroutine_resume(co, f)
end
return co
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(...)中。

function skynet.dispatch_message(...)
local succ, err = pcall(raw_dispatch_message,...)
while true do
local key,co = next(fork_queue)
if co == nil then
break
end
fork_queue[key] = nil
local fork_succ, fork_err = pcall(suspend,co,coroutine_resume(co))
if not fork_succ then
if succ then
succ = false
err = tostring(fork_err)
else
err = tostring(err) .. "\n" .. tostring(fork_err)
end
end
end
assert(succ, tostring(err))
end local function raw_dispatch_message(prototype, msg, sz, session, source)
-- skynet.PTYPE_RESPONSE = 1, read skynet.h
if prototype == then
local co = session_id_coroutine[session]
if co == "BREAK" then
session_id_coroutine[session] = nil
elseif co == nil then
print("prototype, msg, sz, session, source: ", prototype, msg, sz, session, source)
unknown_response(session, source, msg, sz)
else
session_id_coroutine[session] = nil
suspend(co, coroutine_resume(co, true, msg, sz))
end
else
local p = proto[prototype]
if p == nil then
if session ~= then
c.send(source, skynet.PTYPE_ERROR, session, "")
else
unknown_request(session, source, msg, sz, prototype)
end
return
end
local f = p.dispatch
if f then
local ref = watching_service[source]
if ref then
watching_service[source] = ref +
else
watching_service[source] =
end
local co = co_create(f)
session_coroutine_id[co] = session
session_coroutine_address[co] = source
suspend(co, coroutine_resume(co, session,source, p.unpack(msg,sz)))
else
unknown_request(session, source, msg, sz, proto[prototype].name)
end
end
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中实现,代码如下:

local function remove_timeout_cb(...)
end function skynet.remove_timeout(session)
local co = co_create(remove_timeout_cb)
assert(session_id_coroutine[session] ~= nil)
session_id_coroutine[session] = co
end function skynet.timeout(ti, func)
local session = c.intcommand("TIMEOUT",ti)
assert(session)
local co = co_create(func)
assert(session_id_coroutine[session] == nil)
session_id_coroutine[session] = co
return session
end

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

4.测试代码:

local session = skynet.timeout(, function() print("test timeout 10") end)
skynet.remove_timeout(session)
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. 判断 null undefined NaN

    1.判断undefined: var tmp = undefined; if (typeof(tmp) == "undefined"){ alert("undefined ...

  2. 教程less

    http://lesscss.cn/features/ Overview As an extension to CSS, Less is not only backwards compatible w ...

  3. 170209、mysql索引的建立

    用到索引最普通的情况,是为出现在where子句的字段建一个索引.为方便讲述,我们先建立一个如下的表. Code代码如下: CREATE TABLE mytable ( id serial primar ...

  4. python之django直接执行sql语句

    python之django直接执行sql语句 sql = 'select * from stu' info = 模型类.objects.raw(sql)

  5. Elasticsearch集群 管理

    第7章 深入Elasticsearch集群 启动一个Elasticsearch节点时,该节点会开始寻找具有相同集群名字并且可见的主节点.如 果找到主节点,该节点加入一个已经组成了的集群:如果没有找到, ...

  6. You must reset your password using ALTER USER

    mac mysql error You must reset your password using ALTER USER statement before executing this statem ...

  7. Properties 集合

    Map Hashtable Properties 特点: 该集合中的键和值都是字符串类型 集合中的数据可以保存到流中, 或者从流中获取 应用: 通常该集合用于操作以键值对形式存在的配置文件 常用方法: ...

  8. eclipse/IDEA使用maven

    下载,解压(无须安装),配置环境变量,命令行下mvn -v测试.https://www.cnblogs.com/luotaoyeah/p/3764533.html eclipse使用maven 为ec ...

  9. detectron安装+caffe2安装

    detectron安装+caffe2安装 因为想跑一下facebook最近开源的detectron物体检测平台,所以安装caffe2+detectron 总结: 一定要好好看官方安装教程:https: ...

  10. 【我的Android进阶之旅】 解决bug: Expected file scheme in URI: content://downloads/my_downloads/12

    一.错误描述 今天测试MM用HTC手机测试某个模块的时候crash了,抓log后发现是使用DownloadManager下载apk安装包然后自动安装的时候,抛了异常:java.lang.Illegal ...