go:基于时间轮定时器方案
/*
* http://blog.csdn.net/yueguanghaidao/article/details/46290539
* 修改内容:为定时器增加类型和参数属性,修改回调函数类型
*/
package timer
import (
"container/list"
"fmt"
"sync"
"time"
)
//referer https://github.com/cloudwu/skynet/blob/master/skynet-src/skynet_timer.c
const (
TIME_NEAR_SHIFT = 8
TIME_NEAR = 1 << TIME_NEAR_SHIFT
TIME_LEVEL_SHIFT = 6
TIME_LEVEL = 1 << TIME_LEVEL_SHIFT
TIME_NEAR_MASK = TIME_NEAR - 1
TIME_LEVEL_MASK = TIME_LEVEL - 1
)
type Timer struct {
near [TIME_NEAR]*list.List
t [4][TIME_LEVEL]*list.List
sync.Mutex
time uint32
tick time.Duration
quit chan struct{}
}
type Node struct {
expire uint32
/*
* 增加定时器类型和定时器参数
*/
t int
arg string
f func(int, string)
}
var T *Timer
func init() {
timer := New(time.Millisecond * 10)
T = timer
fmt.Println("start timer server...")
go T.Start()
}
func (n *Node) String() string {
return fmt.Sprintf("Node:expire,%d,t:%d,arg:%s", n.expire, n.t, n.arg)
}
func New(d time.Duration) *Timer {
t := new(Timer)
t.time = 0
t.tick = d
t.quit = make(chan struct{})
var i, j int
for i = 0; i < TIME_NEAR; i++ {
t.near[i] = list.New()
}
for i = 0; i < 4; i++ {
for j = 0; j < TIME_LEVEL; j++ {
t.t[i][j] = list.New()
}
}
return t
}
func (t *Timer) addNode(n *Node) {
expire := n.expire
current := t.time
if (expire | TIME_NEAR_MASK) == (current | TIME_NEAR_MASK) {
t.near[expire&TIME_NEAR_MASK].PushBack(n)
} else {
var i uint32
var mask uint32 = TIME_NEAR << TIME_LEVEL_SHIFT
for i = 0; i < 3; i++ {
if (expire | (mask - 1)) == (current | (mask - 1)) {
break
}
mask <<= TIME_LEVEL_SHIFT
}
t.t[i][(expire>>(TIME_NEAR_SHIFT+i*TIME_LEVEL_SHIFT))&TIME_LEVEL_MASK].PushBack(n)
}
}
func (t *Timer) NewTimer(d time.Duration, f func(int, string), tp int, arg string) *Node {
n := new(Node)
n.f = f
n.t = tp
n.arg = arg
t.Lock()
n.expire = uint32(d/t.tick) + t.time
t.addNode(n)
t.Unlock()
return n
}
func (t *Timer) String() string {
return fmt.Sprintf("Timer:time:%d, tick:%s", t.time, t.tick)
}
func dispatchList(front *list.Element) {
for e := front; e != nil; e = e.Next() {
node := e.Value.(*Node)
go node.f(node.t, node.arg)
}
}
func (t *Timer) moveList(level, idx int) {
vec := t.t[level][idx]
front := vec.Front()
vec.Init()
for e := front; e != nil; e = e.Next() {
node := e.Value.(*Node)
t.addNode(node)
}
}
func (t *Timer) shift() {
t.Lock()
var mask uint32 = TIME_NEAR
t.time++
ct := t.time
if ct == 0 {
t.moveList(3, 0)
} else {
time := ct >> TIME_NEAR_SHIFT
var i int = 0
for (ct & (mask - 1)) == 0 {
idx := int(time & TIME_LEVEL_MASK)
if idx != 0 {
t.moveList(i, idx)
break
}
mask <<= TIME_LEVEL_SHIFT
time >>= TIME_LEVEL_SHIFT
i++
}
}
t.Unlock()
}
func (t *Timer) execute() {
t.Lock()
idx := t.time & TIME_NEAR_MASK
vec := t.near[idx]
if vec.Len() > 0 {
front := vec.Front()
vec.Init()
t.Unlock()
// dispatch_list don't need lock
dispatchList(front)
return
}
t.Unlock()
}
func (t *Timer) update() {
// try to dispatch timeout 0 (rare condition)
t.execute()
// shift time first, and then dispatch timer message
t.shift()
t.execute()
}
func (t *Timer) Start() {
tick := time.NewTicker(t.tick)
defer tick.Stop()
for {
select {
case <-tick.C:
t.update()
case <-t.quit:
return
}
}
}
func (t *Timer) Stop() {
close(t.quit)
}
go:基于时间轮定时器方案的更多相关文章
- 经典多级时间轮定时器(C语言版)
经典多级时间轮定时器(C语言版) 文章目录 经典多级时间轮定时器(C语言版) 1. 序言 2. 多级时间轮实现框架 2.1 多级时间轮对象 2.2 时间轮对象 2.3 定时任务对象 2.4 双向链表 ...
- 记录——时间轮定时器(lua 实现)
很长一段时间里,我错误的认识了定时器.无意中,我发现了“时间轮”这个名词,让我对定时器有了新的看法. 我错误的认为,定时器只需要一个 tick 队列,按指定的时间周期遍历队列,检查 tick 倒计时满 ...
- [从源码学设计]蚂蚁金服SOFARegistry之时间轮的使用
[从源码学设计]蚂蚁金服SOFARegistry之时间轮的使用 目录 [从源码学设计]蚂蚁金服SOFARegistry之时间轮的使用 0x00 摘要 0x01 业务领域 1.1 应用场景 0x02 定 ...
- SpringBoot定时任务 - 经典定时任务设计:时间轮(Timing Wheel)案例和原理
Timer和ScheduledExecutorService是JDK内置的定时任务方案,而业内还有一个经典的定时任务的设计叫时间轮(Timing Wheel), Netty内部基于时间轮实现了一个Ha ...
- Kafka中时间轮分析与Java实现
在Kafka中应用了大量的延迟操作但在Kafka中 并没用使用JDK自带的Timer或是DelayQueue用于延迟操作,而是使用自己开发的DelayedOperationPurgatory组件用于管 ...
- Kafka解惑之时间轮 (TimingWheel)
Kafka中存在大量的延迟操作,比如延迟生产.延迟拉取以及延迟删除等.Kafka并没有使用JDK自带的Timer或者DelayQueue来实现延迟的功能,而是基于时间轮自定义了一个用于实现延迟功能的定 ...
- kafka时间轮的原理(一)
概述 早就想写关于kafka时间轮的随笔了,奈何时间不够,技术感觉理解不到位,现在把我之前学习到的进行整理一下,以便于以后并不会忘却.kafka时间轮是一个时间延时调度的工具,学习它可以掌握更加灵活先 ...
- .Net之时间轮算法(终极版)定时任务
TimeWheelDemo 一个基于时间轮原理的定时器 对时间轮的理解 其实我是有一篇文章(.Net 之时间轮算法(终极版))针对时间轮的理论理解的,但是,我想,为啥我看完时间轮原理后,会采用这样的方 ...
- .Net 之时间轮算法(终极版)
关于时间轮算法的起始 我也认真的看了时间轮算法相关,大致都是如下的一个图 个人认为的问题 大部分文章在解释这个为何用时间轮的时候都再说 假设我们现在有一个很大的数组,专门用于存放延时任务.它的精度达到 ...
随机推荐
- kdbg安装使用教程(kali)
一.背景说明 所谓调试者,主要就是下断点.观察变量,不是太复杂的事情也不用太复杂的工具. 但具体到linux平台而言,gdb本来多敲几下命令也不是不可以的事,但是一个屏幕就那么大打印出一堆东西又乱又看 ...
- @NotNull, @NotEmpty和@NotBlank之间的区别是什么?
首先是简要描述: [java] view plain copy@NotNull://CharSequence, Collection, Map 和 Array 对象不能是 null, 但可以是空集(s ...
- linux下stat命令详解
在linux系统下,使用stat(显示inode信息)命令可以查看一个文件的某些信息,我们先来尝试一下. 简单的介绍一下stat命令显示出来的文件其他信息: - File:显示文件名 - Size: ...
- am335x system upgrade uboot sd boot(一)
由于上层应用的需求,需要运行arm docker,在kernel3.2上面还不支持,且编译器的glibc版本比较低的问题,故需要做系统升级 新的内核4.14.40驱动开发和以往有很大的不同,关键在于d ...
- Ubuntu 16.04 中安装谷歌 Chrome 浏览器
http://jingyan.baidu.com/article/335530da98061b19cb41c31d.html 根据教程安装成功!! http://askubuntu.com/quest ...
- JavaScript -基础- 函数与对象(三)数组对象
一.数组对象 1.创建方式 1)创建方式一 var arr=[1,2,3]; 2)创建方式二 var arr2=new Array(1,2,3); 注意: 数组中可以存储任何数据类型.方法类型(Jav ...
- java套接字(socket)实例
客户端socket 流程: 1.连接远程主机 2.发送数据 3.接收数据 4.关闭流与socket连接 实例: import java.io.*; import java.net.Socket; im ...
- 《Python》进程收尾线程初识
一.数据共享 from multiprocessing import Manager 把所有实现了数据共享的比较便捷的类都重新又封装了一遍,并且在原有的multiprocessing基础上增加了新的机 ...
- 十二. Python基础(12)--生成器
十二. Python基础(12)--生成器 1 ● 可迭代对象(iterable) An object capable of returning its members one at a time. ...
- transclude
http://jsfiddle.net/ospatil/A969Z/157/ transclude :true 允许指令内部的dom元素, 保留到 自定义指令的template属性里的含有 ng-t ...