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 之时间轮算法(终极版)
关于时间轮算法的起始 我也认真的看了时间轮算法相关,大致都是如下的一个图 个人认为的问题 大部分文章在解释这个为何用时间轮的时候都再说 假设我们现在有一个很大的数组,专门用于存放延时任务.它的精度达到 ...
随机推荐
- kaggle信用卡欺诈看异常检测算法——无监督的方法包括: 基于统计的技术,如BACON *离群检测 多变量异常值检测 基于聚类的技术;监督方法: 神经网络 SVM 逻辑回归
使用google翻译自:https://software.seek.intel.com/dealing-with-outliers 数据分析中的一项具有挑战性但非常重要的任务是处理异常值.我们通常将异 ...
- x=x+1, x += 1, x++ 效率分析
x = x + 1 效率最低 具体如下: 1. 读取右x的地址 2. x + 1 3. 读取左x的地址 4. 将右值传给左边的x(编译器不认为左x和右x是同一个地址) x += 1 其次 1. 读取右 ...
- 线性回归之决定系数(coefficient of determination)
1. Sum Of Squares Due To Error 对于第i个观察点, 真实数据的Yi与估算出来的Yi-head的之间的差称为第i个residual, SSE 就是所有观察点的residua ...
- MAVEN 自定义骨架
1)根据原由的骨架先创建出一个骨架模板,例如创建一个web框架可以先通过命令 mvn archetype:generate -DarchetypeCatalog=internal 创建出一个web的 ...
- MAVEN ECLIPSE JAR工程
在eclipse 空白处点击鼠标右键选择新建 project 选择maven project: 选择Create a simple project Group ID: Artifact ID:创建项目 ...
- how to get ubuntu current default runlevel
[Purpose] Learning how to get ubuntu current default runlevel [Eevironment] Ubuntu 1 ...
- Java压缩文件
压缩文件 package com.iss.cpf.windmanger.userprivilegeexport.bizlogic; import java.io.BufferedInputStream ...
- spoj220
题解: 后缀数组 把所有串连接起来 二分答案 代码: #include<cstdio> #include<cstring> #include<algorithm> ...
- 【转载】OpenCV 摄像头控制
参考:[OpenCV] -- 简单摄像头操作 - 代码人生 - 博客频道 - CSDN.NET http://blog.csdn.net/qiurisuixiang/article/details/8 ...
- bluemix部署(二)构建kubernetes工作环境
本文接上篇.在bluemix中构建kubernetes容器. 1.创建集群 左上角的三横,选容器,然后创建集群. 注意区域,免费版,给个名字,创建集群吧. 继续正在部署,这个可能要15-30分钟,真不 ...