skynet之伪取消定时器
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之伪取消定时器的更多相关文章
- javascript定时器,取消定时器,及js定时器优化方法
通常用的方法: 启动定时器: window.setInterval(Method,Time) Method是定时调用的js方法 Time是间隔时间,单位是毫秒 取消定时器: clearInterval ...
- JavaScript 定时器 取消定时器
感谢:链接(视频讲解很清晰) 定时器:作用主要是一定时间间隔后,做出相关的变化,例如图片轮播. 目录 两种定时器的使用 两种定时器区别 取消定时器的方法 两种定时器的使用: 方法一:setTimeou ...
- skynet记录6:定时器
稍后填坑 kernel中,每一次时钟中断会trap到kernel code,这个时间间隔称之为jiffies,每秒钟发生的次数为HZ 如果是4核,分配到每个核就是HZ/4 cat /boot/conf ...
- 深入理解定时器系列——被誉为神器的requestAnimationFrame
与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好处呢?为什么requestAnimationFrame被称为神器呢?本文将详 ...
- 深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame
× 目录 [1]引入 [2]特点 [3]使用[4]兼容[5]应用 前面的话 与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好 ...
- GCD定时器
// // ViewController.m // GCD 定时器 // // #import "ViewController.h" NSInteger count = ; @in ...
- iOS--NSTimer设置定时器的两种方法
//方法一: //创建定时器 NSTimer *timer=[NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(next ...
- IOS GCD定时器
提到定时器,NStimer肯定是我们最为熟悉的. 但是NStimer有着很大的缺点,并不准确. 通俗点说,就是它该做他的事了,但是由于其他事件的影响,Nstimer会放弃他应该做的. 而GCD定时器, ...
- IOS中定时器NSTimer的开启与关闭
调用一次计时器方法: myTimer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(scro ...
随机推荐
- [LintCode] 最后一个单词的长度
class Solution { public: /** * @param s A string * @return the length of last word */ int lengthOfLa ...
- 表单验证 靠name获取
表单 靠name获取 <form class="add-form" name="form" action="#" method=&qu ...
- “绝对”妹纸~position
CSS:布局之fixed,relative,absolute 记住abs是跟随 relative的,没有看到position:relative;之前他会一直向上查找. 直到执着的找到relative! ...
- 第5章 IDA Pro
5.1 加载一个可执行文件 默认情况下IDA Pro的反汇编代码中不包含PE头或资源节,可以手动指定加载. 5.2 IDA Pro接口 5.2.1 反汇编窗口模式 二进制模式/图形模式: 图形模式:红 ...
- Oracle Database Documentation
Oracle数据库的发展简史 ORDBMS对象-关系数据库管理系统 Oracle Schema Objects Oracle Schema Objects——Tables——Overview of T ...
- The OpenCV Coding Style Guide
https://github.com/opencv/opencv/wiki/Coding_Style_Guide
- 容灾 RPO RTO
w https://en.wikipedia.org/wiki/Recovery_point_objective A recovery point objective, or “RPO”, is de ...
- django--之登录表单提交
前端代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...
- python学习之路-第八天-文件IO、储存器模块
文件IO.储存器模块 文件IO 代码示例: # -*- coding:utf-8 -*- #! /usr/bin/python # filename:using_file.py poem = '''\ ...
- Python基础总结(字符串常用,数字类型转换,基本运算符与流程控制)
一.字符串常用操作 #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格) name='*egon**' print(name.strip('*'))#移除 name 变量对应 ...