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 之时间轮算法(终极版)
关于时间轮算法的起始 我也认真的看了时间轮算法相关,大致都是如下的一个图 个人认为的问题 大部分文章在解释这个为何用时间轮的时候都再说 假设我们现在有一个很大的数组,专门用于存放延时任务.它的精度达到 ...
随机推荐
- dubbo 自定义 Filter
通过自定义 Filter,可以在 dubbo 调用链中加入特定的逻辑,比如埋点分析调用链. 1. 新建 Filter 类 // @Activate(group = {Constants.CONSUME ...
- CentOS查看安装包会释放哪些文件
1.查看软件包全称(以mysql为例) rpm -qa | grep -i mysql 2.查看释放出的文件(以MySQL-server-5.5.55-1.el6.x86_64为例) rpm -ql ...
- Java反序列化修复方案
1)下载与当前大版本相同的commons-collections包(原来是3.2.x就替换为3.2.2,原来是4.x就替换为4.4.1) 下载链接:http://commons.apache.org/ ...
- pyqt实现滑动开关
https://www.cnblogs.com/feiyangqingyun/p/6035633.html 根据Qt的实现,在PyQt上面实现了滑动开关的控件 import sys from PyQt ...
- Java版本知识
1zip是压缩包,而MSI文件是Windows Installer的数据包,它实际上是一个数据库,包含安装一种产品所需要的信息和在很多安装情形下安装(和卸载)程序所需的指令和数据,只要系统中包含win ...
- python2.x 与 python3.x的区别
从语言的源码角度: python2.x 的源码书写不够规范,且源码有重复,代码的复用率不高; python3.x 的源码清晰.优美.简单 从语言的特性角度: python2.x 默认为ASCII字符编 ...
- python 自然语言处理(三)____条件频率分布
条件频率分布就是频率分布的集合,每个频率分布有一个不同的“条件”,这个条件通常是文本的类别.当语料文本分为几类(文体,主题,作者等)时,可以计算每个类别独立的频率分布,这样,就可以通过条件频率分布研究 ...
- SQL 常用判断语句
我们在做sql更新时,为防止sql重复执行报错,需要对所需要执行的对象进行判断是否存在: 常用判断脚本如下: 判断视图是否存在 IF object_id('viewname') IS not NULL ...
- 4.2计算字符的ASCII碼
Q:终端输入一个字符,输出ASCII碼 #include<stdio.h> int main() { char c; printf("input a charscter:&quo ...
- day13-类的重写和类的私有方法
类的重写 在python中 有时需要进行重写,重写是继承机制中的一个重要部分, 可以重写一般方法也可以重写构造方法,构造方法是用来初始化新创建对象的状态. class A : def hello(se ...