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"命令,只是这样更改的地方较多,但是可以实现彻底取消。

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

  

最新文章

  1. Hadoop学习笔记—15.HBase框架学习(基础知识篇)
  2. 排序系列 之 简单选择排序及其改进算法 —— Java实现
  3. 十五个常用的jquery代码段【转】
  4. GBDT和RF的区别
  5. MRD
  6. each的用法
  7. 百度编辑器UEditor,地址栏传值长度有限-在webConfig配置
  8. Ubuntu 下为 Idea 创建启动图标.
  9. couldn't set tty to ppp discipline invalid argument
  10. pdb文件部分解释
  11. 注册DLL,Unregister DLL
  12. Test注解的两个属性:expected和timeout
  13. 传统web和mvc的区别
  14. DataTable与实体类的转换
  15. freemaker中的map遍历
  16. jfinal afterJFinalStart中执行长久循环操作的解决方案:创建新线程
  17. PymongoDB_study
  18. Django之路
  19. Bootstrap知识记录:排版样式
  20. HTML5 学习01——浏览器问题、新元素

热门文章

  1. eslint Rules
  2. 前端代码tomcat下简单部署
  3. SQL server-自增主键
  4. pip与apt-get
  5. BaseAction 类
  6. 小木虫emuch遭封禁,新域名muchong.com尚可用
  7. make编译五
  8. keras中 LSTM 的 [samples, time_steps, features] 最终解释
  9. Tornado模块分类
  10. PageObjects 设计模式