skynet的定时器
2015-11-04 16:32
399 查看
skynet的定时器入口只有一个,其精度大小为0.001
在第一行就像C语言层注册了一个定时器,其后就创建一个执行函数为传入的func的协程。之后再其与返回的session关联起来。
在C语言层主要是用linux的内核实现的方式,假定一个定时器要经过interval个时钟滴答后才到期(interval=expires-jiffies),则Linux采用了下列思想来实现其动态内核定时器机制:对于那些0≤interval≤255的定时器,Linux严格按照定时器向量的基本语义来组织这些定时器,也即Linux内核最关心那些在接下来的255个时钟节拍内就要到期的定时器,因此将它们按照各自不同的expires值组织成256个定时器向量。而对于那些256≤interval≤0xffffffff的定时器,由于他们离到期还有一段时间,因此内核并不关心他们,而是将它们以一种扩展的定时器向量语义(或称为“松散的定时器向量语义”)进行组织。所谓“松散的定时器向量语义”就是指:各定时器的expires值可以互不相同的一个定时器队列。 代码如下
在到期后,C层会调用dispatch_list()向lua层推送一条回应型消息,这条消息也会通过上一篇分析过的流程调用skynet.dispatch_message()来处理。
比较奇怪的是这样处理的话如果在前面已有较多消息待处理的时候,可能会导致最终调用定时器函数的时间超过预期。唔但是就目前来看似乎也无法避免这种情况。
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 end
在第一行就像C语言层注册了一个定时器,其后就创建一个执行函数为传入的func的协程。之后再其与返回的session关联起来。
在C语言层主要是用linux的内核实现的方式,假定一个定时器要经过interval个时钟滴答后才到期(interval=expires-jiffies),则Linux采用了下列思想来实现其动态内核定时器机制:对于那些0≤interval≤255的定时器,Linux严格按照定时器向量的基本语义来组织这些定时器,也即Linux内核最关心那些在接下来的255个时钟节拍内就要到期的定时器,因此将它们按照各自不同的expires值组织成256个定时器向量。而对于那些256≤interval≤0xffffffff的定时器,由于他们离到期还有一段时间,因此内核并不关心他们,而是将它们以一种扩展的定时器向量语义(或称为“松散的定时器向量语义”)进行组织。所谓“松散的定时器向量语义”就是指:各定时器的expires值可以互不相同的一个定时器队列。 代码如下
static void add_node(struct timer *T,struct timer_node *node) { uint32_t time=node->expire; uint32_t current_time=T->time; if ((time|TIME_NEAR_MASK)==(current_time|TIME_NEAR_MASK)) { link(&T->near[time&TIME_NEAR_MASK],node); } else { int i; uint32_t mask=TIME_NEAR << TIME_LEVEL_SHIFT; for (i=0;i<3;i++) { if ((time|(mask-1))==(current_time|(mask-1))) { break; } mask <<= TIME_LEVEL_SHIFT; } link(&T->t[i][((time>>(TIME_NEAR_SHIFT + i*TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)],node); } }
在到期后,C层会调用dispatch_list()向lua层推送一条回应型消息,这条消息也会通过上一篇分析过的流程调用skynet.dispatch_message()来处理。
static inline void dispatch_list(struct timer_node *current) { do { struct timer_event * event = (struct timer_event *)(current+1); struct skynet_message message; message.source = 0; message.session = event->session; message.data = NULL; message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT; skynet_context_push(event->handle, &message); struct timer_node * temp = current; current=current->next; skynet_free(temp); } while (current); }
比较奇怪的是这样处理的话如果在前面已有较多消息待处理的时候,可能会导致最终调用定时器函数的时间超过预期。唔但是就目前来看似乎也无法避免这种情况。
参考链接
[1]http://www.tuicool.com/articles/qui2ia相关文章推荐
- 详解Lua中的表的概念及其相关操作方法
- Lua编程示例(二):面向对象、metatable对表进行扩展
- 把Lua编译进nginx步骤方法
- Lua脚本自动生成APK包
- Lua中的元表(metatable)、元方法(metamethod)详解
- Lua中的metatable介绍
- Lua中ipair和pair的区别
- Lua中的函数精讲笔记
- 浅谈Lua的面向对象特性
- 详解Lua中的变量相关知识点
- Lua脚本语言入门笔记
- Lua脚本调用外部脚本
- 详解Lua中的if语句的使用方法
- Lua中调用函数使用点号和冒号的区别
- Lua中的闭合函数、非全局函数与函数的尾调用详解
- Lua中强大的元方法__index详解
- Lua中调用C++函数示例
- Lua面向对象之类和继承浅析
- Lua性能优化技巧(一):前言
- Lua中获取table长度问题探讨